sdaps-1.9.8/0000755000175000000660000000000013611127124013375 5ustar benjaminlock00000000000000sdaps-1.9.8/COPYING0000644000175000000660000000065713575707425014461 0ustar benjaminlock00000000000000This program is free software. Different licenses apply to different parts of the program. Most of the files are distributed under the conditions of the GPLv3 or any later versions (see COPYING.GPLv3) Files in the "tex" directory are distributed under the conditions of the LPPLv1.3c or any later version. All files should have a corresponding copyright header, if one is missing please write the authors to clarify the license.sdaps-1.9.8/MANIFEST.in0000644000175000000660000000161713367301321015141 0ustar benjaminlock00000000000000include MANIFEST.in include NEWS include README.md include TROUBLESHOOTING include COPYING include sdaps.py include tex/class/*.dtx include tex/class/*.ins include tex/class/*.lua include tex/class/*.tex include tex/class/*.sty include tex/class/examples/*.tex include tex/class/testfiles/*.lvt include tex/class/testfiles/*.tlg recursive-include sdaps *.py *.ui *.c *.h recursive-include po *.pot POTFILES.skip POTFILES.in *.po recursive-include tex/po *.pot POTFILES.skip POTFILES.in *.po include test/run-test.sh include test/run-test-locally.sh recursive-include test/data *.internetquestions *.odt *.pdf *.tif recursive-include test/data *.tex *.csv questionnaire_ids recursive-include test/data/info_files * include custom-scripts/README recursive-include custom-scripts *.py include examples/example.tex include examples/example.tif include test/data/tex/code128_test_ids include tex/tex_translations.in sdaps-1.9.8/NEWS0000644000175000000660000003676213611126743014120 0ustar benjaminlock00000000000000Overview of Changes in SDAPS 1.9.8 ================================== This release breaks backward compatibility in a few small ways. For example the "style" parameter of the LaTeX class was renamed to "sdaps_style". Also unrelated to this release but still noteworthy is that the LaTeX class has been uploaded to CTAN and has also been added to TeX Live. There will be a few more related changes to this so that SDAPS will pick up the system version of the LaTeX class by default. Important changes: * LaTeX: Class now takes sdaps_style as argumen instead of style * LaTeX: Class will now always report the correct page count (#192) * LaTeX: Improve spacing of multiline choicequestion items * LaTeX: Disable header repetition in rangearray/markgroup questions (#21) * Fix issue with SQL schema (#189) * Fix issues with transformation matrix calculation (#195) * Allow adjusting corner marks in GUI (#194) * Allow running box recognition from GUI Overview of Changes in SDAPS 1.9.7 ================================== This is a smaller bugfix release mostly to solve compatibility issues with older SDAPS versions. Important changes: * Slightly improved command line parsing * Fix various data format migration issues (#173, #175) * Fix the reset and reorder commands to work again (#168) * Update LaTeX class with a few minor fixes New and updated languages: * Portuguese Overview of Changes in SDAPS 1.9.6 ================================== This is the next release to stabilize SDAPS in the run up to a 2.0 release. There are a number of smaller changes that change behaviour, so again, take some care when upgrading. Important changes: * Allow adding review comments on whole sheets and questions (#148) * Allow specifying the LaTeX engine used to compile the project (#150) * Reorder CSV command parameters to match new layout * Fix printing of state when an error occurs during setup (#163) * Fix LaTeX class build script hanging when l3build is missing (#166, #153) * Default to not align all group environments in a document (sdaps-class#15) * Allow disabling all recognition related markings (sdaps-class#14) * Add basic support for reading QR codes as part of questions (#2) New and updated languages: * Norwegian Bokmål * Portuguese * Portuguese (Brazil) Overview of Changes in SDAPS 1.9.5 ================================== WARNING: This release breaks compatibility in a number of different ways, please be careful when upgrading. The most important change is that the command line argument order has been changed. The SDAPS command that is to be run is now the first argument, and the project directory is second. There have also been a number of changes to the LaTeX class, including new instruction texts that have not yet been translated to all languages. Important changes: * Rework command line handling * Default instructions for filling out the form are updated * Margin handling in LaTeX class is improved * "info" environment padding at the top of the page is improved * Improved rotated header layouter for array question types New and updated languages: * Korean * Dutch * Norwegian Bokmål * French * German Overview of Changes in SDAPS 1.9.4 ================================== Important changes: * Ensure box IDs are unique (#142) * Fix variable name handling of the single choice questions (#141) * Make "verified" a property of each image, all images need to be marked as verified * Add support for right to left languages: - Implement RTL switching in LaTeX - Make metadata file line numbered - Fix anotation line length (and indentation for RTL languages) - Rework choicequestion layout New and updated languages: * Romanian * Sinhala * Spanish Overview of Changes in SDAPS 1.9.3 ================================== This is a bugfix release. Important changes: * Fix TEXINPUTS environment variable handling (issue #120) * convert: Improve DPI selection and detection for PDF conversion * latex: Improved whitespace in rangearray with alternative choices * latex: Handle \ior_get_str:NN deprecation * latex: Fix single choice question metadata export New and updated languages: * Polish Overview of Changes in SDAPS 1.9.2 ================================== This is a new unstable release porting SDAPS to Python 3 and modifying the data storage format. This release is incompatible to any prior release. It can be considered the first 2.0 alpha release though. Important changes: * ODT support has been dropped entirely (due to missing dependencies for Python 3) * Data storage has been switched to sqlite storing json serialised objects * Correctly calculate standard deviation (issue #111) * Updated LaTeX class with new features and fixes - Documentation improvements - Add \qid back for querying the current questionnaire ID (Paulo Matias) - Requires variable handling and auto numbering - Add range specification to choicegroup questions only showing certain choices - Improved layouting of sdapsarray - Allow setting checkbox count of singlemark questions * Add a few helpers for packaging New and updated languages: * Norwegian bokmål * Spanish * Italian * Ukrainian Overview of Changes in SDAPS 1.9.1 ================================== This is a new unstable release pulling in a lot of fixes. Please note that it is incompatible to the previous 1.9.0 release as the fixes to the class will result in the survey IDs to become different. Important changes: * Fix repetition of questionnaires * Fixes to make class work with TeXlive 2017-08-08 * Fix build to not install the TeX class in the users home directory * Fix LaTeX report generation (#108) * Fixes and tests of CSV import and exporter * Improve CSV export to include more information about sheets * Change default style to QR code Overview of Changes in SDAPS 1.9.0 ================================== Beta release that includes the new class. Generating a new project will now need to use the sdapsclassic class to work fine. Please see http://sdaps.org/class-doc and https://github.com/sdaps/sdaps-class for some more information. Overview of Changes in SDAPS 1.1.11 =================================== Mostly a bugfix release again. The most important fix (preventing dataloss) is that the data is now written atomically. This means that aborting an SDAPS run should not result in a corrupted database anymore. Important changes: * model: Write survey file atomically (#79) * image: compatibility with older glib versions * csv: Import code fixes (#79) * latex: Work around manual enumeration breaking automatic numbering * setup: Create nested directories instead of only one leve * convert: Support landscape questionnaires (#88) New and updated languages: * Arabic Overview of Changes in SDAPS 1.1.10 =================================== Again, mostly a bugfix release. One thing to note is that if you are using small fields (i.e. choiceitemtext) is that single characters/digits can sometimes be detected as only dirty. So if you want to use fields with only a single character, then it is likely a good idea to fine tune the minimum size of writing and other aspects of freeform field recognition. Important changes: * latex: Fix search paths (#63) * latex report: Fix formatting issues * gui: Fix broken display in some corner cases (#67) * gui: Ensure dialogs are on top of the main window (#66) * csv: Options to export recognition quality * Allow filtering based on string replacements for freeform fields (#69) * latex: Fix encoding issues for some special characters (#70) * latex: Allow smaller choiceitemtext elements (#68) New and updated languages: * French * German * Portuguese (Brazil) * Dutch Overview of Changes in SDAPS 1.1.9 ================================== Mostly a bugfix release. Important changes: * csv: PNG export for complete questions * Fix various encoding issues (#59, #61) * dynamic kfill size for barcode detection * Fix LaTeX search path regression (see #11) New and updated languages: * Spanish Overview of Changes in SDAPS 1.1.8 ================================== Important changes: * recognize: prevent division by zero error * recognize: try barcode detection both with and without kfill * recognize: ignore data from previous run * csv: Add support to specify delimiter * csv, ids: allow output to any file including stdout * gui: properly escape all strings New and updated languages: * German Overview of Changes in SDAPS 1.1.7 ================================== The most important change in this release is that the import of image data has been simplified. SDAPS can now do an image format conversion automatically as part of the "add" command, removing the necessity of using "convert" or some other external method to preprocess the images. As before, this feature requires OpenCV. Another change is that SDAPS now imports PDF files directly. If a PDF file contains a full page image (i.e. a scanned document) then this image is used directly to prevent image quality loss due to resampling. This feature requires poppler to be installed. Overall these changes make it a lot easier to work with different scanners. It is now only neccessary to pass the "--convert" option to the "add" command to add files that are not already in the expected format. Important changes: * stamp: Fix re-stamping all IDs * add: Implement conversion feature (--convert option) * convert: Add support for reading PDF files New and updated languages: * German * Portuguese (Brazil) Overview of Changes in SDAPS 1.1.6 ================================== This release adds support to use QR code instead of Code-128. The main advantage is that QR-Code contains redundancy so that recognition should be more reliable even with bad scans. Another important change is that it is now possible to select different modes for checkbox detection without modifying the source code. This should simplify the usage of SDAPS in certain cases. Feedback for optimizing the different modes is of course welcome. The thresholds have not been tested extensively. Important changes: * Support for QR-Code based IDs has been added ("qr" style) * csv export: Allow export of freeform textboxes as images * Updated example and testcase for newer multicol versions * tex: Fix writing sdaps file for all macros. * Allow selection of different checkbox detection modes. New and updated languages: * Portoguese (copy of Portoguese (Brazil)) * German Overview of Changes in SDAPS 1.1.5 ================================== Important changes: * report: Fix import of PIL (Florian Rinke) * odt: Fix annotation on setup failure * gui: Fix memory leak * latex: Small improvements to class usability * translations: Fix LaTeX dictionary names. New and updated languages: * Finnish * German Overview of Changes in SDAPS 1.1.4 ================================== This is mostly a bugfix and translations release, as there was still some fallout from the refactoring done in the last release. Thanks to everyone who submitted patches to fix these! Important changes: * dependency, build, and import fixes (#44, #46, and more) * fix layout changes in LaTeX and example (introduced in 1.1.2) * report: fix non A4 paper sizes (issue #41) New and updated languages: * Portuguese (Brazil) * Spanish * German Overview of Changes in SDAPS 1.1.3 ================================== With this release SDAPS has been restructured internally. There are two reasons for doing this. The first is to improve the API which simplifies the usage of it in custom scripts. Another point is that the old code was incompatible with the import handling of python 3. So doing this change is also a prerequisite for a future port to python 3.x. Other changes include: * GUI: Fix an offset error with new GTK+ versions * GUI: Improved keyboard navigation (issue #30) * GUI: Improved mouse handling and overlay drawing * GUI: Show the questionnaire ID on the right side * GUI: Sort images by page number * LaTeX: Improved unicode support * LaTeX: Fixed precision issues in report generation * LaTeX: Fixed some whitespace issues in the LaTeX class * ODT: When stamping a single document, keep forms intact * reorder: Fix reordering of simplex documents * recognize: Slight changes in the OMR heuristics. * Fixed issues in the upgrade routine New and updated translations: * German * Spanish Overview of Changes in SDAPS 1.1.2 ================================== This release brings a lot of small improvements, but also some new features. The main new feature is the addition of a "convert" module, which can be used to convert non-monochrome scans into monochrome images for later processing. This module is also able to apply 3D-transformations as they are neccessary when the source image was done using a camera. This new module requires OpenCV. Note that using a feed scanner is still prefered to this method. Other changes include: * LaTeX: Fix compilation of large documents (by suppressing position output) * LaTeX: Fix multicolumn items and cline at the start of choicequestions * ODT: Custom styling in answers and question is now possible. * Various improvements and fixes in the corner mark detection code * New "custom" style which can be used when customizing the behaviour of SDAPS * A PDF with annotations will now be created if there was an error during setup * An issue in the base dir search code that affected OSX has been fixed New and updated translations: * Arabic Overview of Changes in SDAPS 1.1.1 ================================== Important changes: * Fix the "min coverage" heuristic * Export text as UTF-8 in CSV files (issue #23) * report: Ignore empty sheets * Add "verified" and "recognized" flags for sheets. Recognition will not be done by default if either flag is set. * GUI: Pressing "Enter" now sets the "verified" flag * LaTeX class: Paint inner area of boxes white. This is required to allow background coloring. And a couple more small bugfixes and additions. New and updated translations: * German * Dutch Overview of Changes in SDAPS 1.1.0 ================================== This release brings a lot of new goodies. As a development release it may still be a bit rough in a few places, but everyone is invited to play with it and report any issues :-) Important changes: * Support for duplex scanning of simplex questionnaires (issue #1) * Freeform fields can be manually replaced with text (issue #14) * Mark questions can now have an arbitrary checkbox count (issue #7) * Correctly pick new questionnaire IDs during stamp (issue #22) * Report paper size is now locale dependend (issue #9) * LaTeX: classes are now translatable using PO files * GUI: Widget based view of the questionnaire * LaTex report: Allow the generated LaTeX to be stored New and updated translations: * German Overview of Changes in SDAPS 1.0.3 ================================== Bugfix so that the SDAPS class works with older PGF versions. Overview of Changes in SDAPS 1.0.2 ================================== Bugfix so that the commands work fine without a TTY. Overview of Changes in SDAPS 1.0.1 ================================== Only depend on distutils and pkg_resources if doing a local run. Overview of Changes in SDAPS 1.0.0 ================================== This is the first release of SDAPS. It is not fully compatible to older versions. Anyone with existing projects should *not* upgrade. Important changes: * LaTeX: Improved spacing * LaTeX: Fix position extraction code * LaTeX/core: Support for circular/elliptical checkboxes * LaTeX: now supports multicolumn layouts * LaTeX: new command to draw a filled checkbox New and updated translations: * German * Arabic sdaps-1.9.8/PKG-INFO0000644000175000000660000000102213611127124014465 0ustar benjaminlock00000000000000Metadata-Version: 1.0 Name: sdaps Version: 1.9.8 Summary: Scripts for data acquisition with paper-based surveys Home-page: http://sdaps.sipsolutions.net Author: Benjamin Berg, Christoph Simon Author-email: benjamin@sipsolutions.net, post@christoph-simon.eu License: GPL-3 Description: SDAPS is a tool to carry out paper based surveys. You can create machine readable questionnaires using LaTeX. It also provides the tools to later analyse the scanned data, and create a report. Platform: UNKNOWN sdaps-1.9.8/README.md0000644000175000000660000000654313367301321014665 0ustar benjaminlock00000000000000# SDAPS This Program can be used to carry out paper based surveys. SDAPS uses a specialised LaTeX class to define questionnaires. This is tightly integrated and is an easy way to create machine readable questionnaires. After this, the program can create an arbitrary number of (unique) questionnaires that can be printed and handed out. After being filled out, you just scan them in, let sdaps run over them, and let it create a report with the results. ## Requirements Depending on what part of SDAPS you use, different dependencies are required. general (including recognize): * Python 3.6 * distutils and distutils-extra * python3-cairo (including development files) * libtiff (including development files) * pkg-config * zbarimg binary for "code128" and "qr" styles * python3 development files graphical user interface (gui): * GTK+ and introspection data * python3-gi reportlab based reports (report): * reportlab * Python Imaging Library (PIL) LaTeX based questionnaires (setup_tex/stamp): * pdflatex and packages: * PGF/TikZ * translator (part of beamer) * and more LaTeX based reports: * pdflatex and packages: * PGF/TikZ * translator (part of beamer) * siunitx Import of other image formats (convert, add --convert): * python3-opencv * Poppler and introspection data * python3-gi Debug output (annotate): * Poppler and introspection data * python3-gi ## Installation You can install sdaps using "./setup.py install". The C extension will be compiled automatically, but of course you have to have all the dependencies installed for this to work. Please note that this git repository uses submodules to pull in the LaTeX code. This means you need to run $ git submodule init and then run $ git submodule update to checkout and update the repository after a pull. Alternatively, do the initial clone using "git clone --recursive". ## Standalone execution As an alternative to installing sdaps it is also supported to run it without installation. To do this run "./setup.py build" to build the binary modules and translation. After this execute sdaps using the provided "sdaps.py" script in the toplevel directory. ## Using SDAPS Please run sdaps with "--help" after installing it for a list of commands. Also check the website http://sdaps.org for some examples. ## Quality of the recognition The quality of the recognition in SDAPS is quite good in my experience. There is a certain amount of wrong detections, that mostly arise from people not checking or filling out the boxes correctly. For example: * The cross is not inside the checkbox, but next to it * People cross the same box multiple times * People use very thick pens * Filling out is not done properly As you can see, most of the errors arise from the possibility to correct wrong marks by filling out checkboxes. SDAPS tries to be smart about this by using different heuristics to detect the case, but it is not foolproof. Suggestions on how to decrease the error rate are of course welcome. ### Matrix Errors It can happen that SDAPS is not able to calculate the transformation matrix which transforms the pixel space of the image into the mm coordinate system used internally. If this happens the affected pages cannot be further analysed. It is usually possible to manually correct them using the GUI, but that can be quite tedious. See also TROUBLESHOOTING for some more information. sdaps-1.9.8/TROUBLESHOOTING0000644000175000000660000000435613346275473015637 0ustar benjaminlock00000000000000What to do when things go wrong =============================== In general, you can try to adjust the magic values in defs.py to improve recognition and work around errors that you get. If you need to change something, pĺease drop us a line. Matrix could not be recognized ------------------------------ This means SDAPS could not find all four edge markers. Please have a look at the following: * Check that the scan is OK. * Does it have black/white lines? This can happen in the scanner is not clean. * Check that the resolution is set to 300dpi * Check there is no black line at one side * Try modifying the magic recognition parameters in defs.py image_line_width and image_line_coverage. However, it is unlikely that this is neccessary. Recognition quality is bad -------------------------- If you want to analyse the heuristics you can run the tool "boxgallery". $ sdaps project_dir boxgallery This creates a PDF for every heuristic, showing the returned value. Boxes with a bold label are considered checked by SDAPS. You can adjust the criteria by changing the checkbox_metrics dictionary in defs.py. Each of the entries is a list that maps the heuristic to checkbox and quality measures. Should you find better values, please share them! NOTE: If you want to remove the errors arising from the possibility to correct mistakes, you can choose a different checkbox detection mode that disallows corrections. Please have a look at the "checkmode" parameter. Text boxes are recognized even though they are empty ---------------------------------------------------- This can happen because of dirt on the page or because the scanner is not very accurate and the outline is detected as writing. If dirt is detected, try to adjust the textbox_scan_* values in defs.py. If the outline is detected than probably something worst is going on. You can adjust the textbox_*_padding values, or adjusting the image_line_* values might also help (as these are used to find the corners of the textbox). If the above does not help ========================== Mail the authors :-) It may be neccessary to have all the data to help. So if you can try to always provide examples where things fail. NOTE: It may be that this document is not always up to date.sdaps-1.9.8/bin/0000755000175000000660000000000013611127124014145 5ustar benjaminlock00000000000000sdaps-1.9.8/bin/sdaps0000755000175000000660000000163413367301321015212 0ustar benjaminlock00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright (C) 2008, Christoph Simon # Copyright (C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import sys import sdaps sys.exit(sdaps.main()) sdaps-1.9.8/custom-scripts/0000755000175000000660000000000013611127124016374 5ustar benjaminlock00000000000000sdaps-1.9.8/custom-scripts/README0000644000175000000660000000425313465375077017303 0ustar benjaminlock00000000000000========================= WARNING ========================= These scripts were designed for earlier versions of SDAPS. While the idea was that they operate without modifying the underlying database, this is currently *not* the case. Again, because of changes to the data storage, the survey is actually updated *immediately* and changes done by these scripts *will* be written to disk. Also, they are probably broken to begin with … With that warning, the old README --------------------------------- These are examples of what can be done by using the SDAPS modules directly. This may be useful for specialized use cases, where one wants a custom behaviour. Note that these scripts do use internal APIs that may change in the future. That said, these it may also make sense to simplify them or add the functionallity that they provide into the main program or a separate scripting interface. I guess this is a political problem about whether the internal APIs should be consumable by end users or not. There are currently two scripts that work on image data. Both of them will not modify the SDAPS project that they are exected on, but instead only output information about the scanned data. sdaps-identify.py ----------------- Arguments: SDAPS project and one or more tif files. Returns: For each set of images basic information is printed. This contains the IDs, information about rotation and the transformation matrix. This returns the basic data about each image. It does not contain data from checkboxes, and SDAPS should usually output the correct information even if it is for a different survey. sdaps-recognize.py ------------------ Arguments: SDAPS project and one or more tif files. Returns: A flat representation of all the values of checkboxes for each questionnaire. For each checkbox you get the following values: GlobalID, SurveyID, QuestionnaireID, Checkbox Identifier, Checkbox State, Recognition Quality This script runs the recognition and dumps much of the internal data out to stdout. Note that raw image data (from freeform text fields) is currently ignored. Code could easily be added which dumps these out to PNG files, or even base64 encoded strings if required. sdaps-1.9.8/custom-scripts/sdaps-identify.py0000755000175000000660000000520413367301321021676 0ustar benjaminlock00000000000000#!/usr/bin/env python3 # -*- coding: utf8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright (C) 2008, Christoph Simon # Copyright (C) 2012, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import sys import os # Use the following and local_run=True below to run without installing SDAPS #sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), '..')) import sdaps #sdaps.init(local_run=True) sdaps.init() from sdaps import model from sdaps import image # We need a survey that has the correct definitions (paper size, duplex mode) # Assume the first argument is a survey survey = model.survey.Survey.load(sys.argv[1]) # We need the recognize buddies, as they are able to identify the data from sdaps.recognize import buddies # A sheet object to attach the images to sheet = model.sheet.Sheet() survey.add_sheet(sheet) images = [] for file in sys.argv[2:]: num_pages = image.get_tiff_page_count(file) for page in range(num_pages): images.append((file, page)) if len(images) == 0: # No images, simply exit again. sys.exit(1) def add_image(survey, tiff, page): img = model.sheet.Image() survey.sheet.add_image(img) # SDAPS assumes a relative path from the survey directory img.filename = os.path.relpath(os.path.abspath(tiff), survey.survey_dir) img.orig_name = tiff img.tiff_page = page while images: # Simply drop the list of images again. sheet.images = [] add_image(survey, *images.pop(0)) if survey.defs.duplex: add_image(survey, *images.pop(0)) sheet.recognize.recognize() for img in sheet.images: print(img.orig_name, img.tiff_page) print('\tPage:', img.page_number) print('\tRotated:', img.rotated) print('\tMatrix (px to mm):', img.raw_matrix) print('\tSurvey-ID:', sheet.survey_id) print('\tGlobal-ID:', sheet.global_id) print('\tQuestionnaire-ID:', sheet.questionnaire_id) print() # And, we simply quit, ie. we don't save the survey sdaps-1.9.8/custom-scripts/sdaps-overlay.py0000755000175000000660000000754513367301321021556 0ustar benjaminlock00000000000000#!/usr/bin/env python3 # -*- coding: utf8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright (C) 2008, Christoph Simon # Copyright (C) 2015, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import sys import os import cairo import math # Use the following and local_run=True below to run without installing SDAPS #sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), '..')) import sdaps #sdaps.init(local_run=True) sdaps.init() from sdaps import model from sdaps import image from sdaps import matrix survey = model.survey.Survey.load(sys.argv[1]) counter = 1 def ellipse(cr, x, y, width, height): cr.save() cr.translate(x + width / 2.0, y + height / 2.0) line_width = cr.get_line_width() cr.scale(width / 2.0, height / 2.0) cr.arc(0, 0, 1.0, 0, 2*math.pi) cr.close_path() # Restore old matrix (without removing the current path) cr.restore() def generate_pdf(): global counter global survey questionnaire = survey.questionnaire sheet = survey.sheet # Use the questionnaire ID, if not there, give up? if sheet.questionnaire_id is not None: pdf_name = 'overlay-%s.pdf' % sheet.questionnaire_id else: pdf_name = 'overlay-%04i.pdf' % counter counter += 1 surface = cairo.PDFSurface(pdf_name, survey.defs.paper_width * 72 / 25.4, survey.defs.paper_height * 72 / 25.4) cr = cairo.Context(surface) # Transform to mm space cr.scale(72 / 25.4, 72 / 25.4) for p in range(questionnaire.page_count): # 1 based page numbers p += 1 # Get the current image img = sheet.get_page_image(p) if img is None: print("no image") cr.show_page() continue # Render the image on the background, we take the easy way and paint it # correctly. i.e. so that the markings on top are at the expected # positions. It would likely be faster to only scale the image instead. # (And not much harder, just needs the correct transformation for the # other markings) cr.save() cr.transform(img.matrix.px_to_mm()) cr.set_source_rgb(0, 0, 0) cr.mask_surface(img.surface.load_uncached(), 0, 0) cr.restore() # Now render all checked checkboxes, for now inline here. for qobj in questionnaire.qobjects: for box in qobj.boxes: if box.data.state: if box.page_number != p: continue if not isinstance(box, model.questionnaire.Checkbox): continue # 1pt line width cr.set_line_width(1 / 25.4) x, y, width, height = box.data.x, box.data.y, box.data.width, box.data.height x -= width / math.sqrt(2) / 2 y -= height / math.sqrt(2) / 2 width += width / math.sqrt(2) height += height / math.sqrt(2) ellipse(cr, x, y, width, height) cr.set_source_rgb(1, 0, 0) cr.stroke() cr.show_page() del cr surface.flush() del surface survey.iterate_progressbar(generate_pdf) sdaps-1.9.8/custom-scripts/sdaps-recognize.py0000755000175000000660000000571213367301321022054 0ustar benjaminlock00000000000000#!/usr/bin/env python3 # -*- coding: utf8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright (C) 2008, Christoph Simon # Copyright (C) 2012, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import sys import os # Use the following and local_run=True below to run without installing SDAPS #sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), '..')) import sdaps #sdaps.init(local_run=True) sdaps.init() from sdaps import model from sdaps import image # Assume the first argument is a survey survey = model.survey.Survey.load(sys.argv[1]) # We need the recognize buddies, as they are able to identify the data from sdaps.recognize import buddies # A sheet object to attach the images to sheet = model.sheet.Sheet() survey.add_sheet(sheet) images = [] for file in sys.argv[2:]: num_pages = image.get_tiff_page_count(file) for page in range(num_pages): images.append((file, page)) if len(images) == 0: # No images, simply exit again. sys.exit(1) def add_image(survey, tiff, page): img = model.sheet.Image() survey.sheet.add_image(img) # SDAPS assumes a relative path from the survey directory img.filename = os.path.relpath(os.path.abspath(tiff), survey.survey_dir) img.orig_name = tiff img.tiff_page = page while images: # Simply drop the list of images again. sheet.images = [] add_image(survey, *images.pop(0)) if survey.defs.duplex: add_image(survey, *images.pop(0)) else: add_image(survey, 'DUMMY', -1) # Run the recognition algorithm over the given images survey.questionnaire.recognize.recognize() for qobject in survey.questionnaire.qobjects: if isinstance(qobject, model.questionnaire.Question): # Only print data if an image for the page has been loaded if survey.sheet.get_page_image(qobject.page_number) is None: continue for box in qobject.boxes: print("%s,%s,%s,%s,%i,%f" % ( survey.sheet.global_id, survey.sheet.survey_id, survey.sheet.questionnaire_id, '_'.join([str(num) for num in box.id]), int(box.data.state), float(box.data.quality))) print() # And, we simply quit, ie. we don't save the survey sdaps-1.9.8/examples/0000755000175000000660000000000013611127124015213 5ustar benjaminlock00000000000000sdaps-1.9.8/examples/example.tex0000644000175000000660000001421313575707425017412 0ustar benjaminlock00000000000000\documentclass[ % Babel language, also used to load translations english, % Use A4 paper size, you can change this to eg. letterpaper if you need % the letter format. The normal methods to modify the paper size should % be picked up by SDAPS automatically. % a4paper, % setting this might break the example scan unfortunately % letterpaper % % If you need it, you can add a custom barcode at the center %globalid=SDAPS, % % And the following adds a per sheet barcode at the bottom left %print_questionnaire_id, % % You can choose between twoside and oneside. twoside is the default, and % requires the document to be printed and scanned in duplex mode. %oneside, % % With SDAPS 1.1.6 and newer you can choose the mode used when recognizing % checkboxes. valid modes are "checkcorrect" (default), "check" and % "fill". %checkmode=checkcorrect, % % The following options make sense so that we can get a better feel for the % final look. pagemark, stamp]{sdapsclassic} \usepackage[utf8]{inputenc} % For demonstration purposes \usepackage{multicol} \author{The Author} \title{The Title} \begin{document} % Everything you do should be done inside the questionnaire environment. % If you don't like the default text at the beginning of each questionnaire % you can remove it with the optional [noinfo] parameter for the environment \begin{questionnaire} % There is a predefined "info" style to hilight some text. \begin{info} You can create a customized information element similar to the standard one using the \texttt{info} environment. By adding \texttt{[noinfo]} to the \texttt{questionaire} environment you can replace the predefined information field with your own. \end{info} % Use \addinfo to add metadata (which is printed on the report later on) \addinfo{Date}{10.03.2013} % You can structure the document using sections. You should not use % subsections yourself, as these are used to typeset question text. \section{Range Questions} % Lets ask some questions. % \singlemark creates a single range (1-5) question. \singlemark{How often do you use SDAPS?}{never}{daily} % Now we would like to ask multiple range questions that are similar. We % can use a markgroup environment to typeset many range questions under % one heading. \begin{markgroup}{What do you think about the following aspects of \LaTeX?} \markline{equation syntax}{bad}{good} \markline{rendered equations}{ugly}{beautiful} \markline{ease of use}{hard}{easy} \end{markgroup} \section{Choice Questions} We can also give users a question with predefined choices. Such a list of choices is typesetted using a tabularx environment with equally sized columns. Items can span multiple columns. \begin{choicequestion}[cols=3]{Which of the following Open Source Optical Mark Recognition software packages have you heard about?} \choiceitem{SDAPS} \choicemulticolitem{2}{Auto Multiple Choice} \choiceitem{QueXF} % Insert a text field. The freeform box automatically scales horizontally % The first parameter is the height of the box. The second parameter % is the amount of columns it should span. \choiceitemtext{1.2cm}{2}{Other:} \end{choicequestion} % And a more compact way of doing it; similar to markgroup \begin{choicegroup}{Which software do you prefere for the following tasks?} % We have to add the possible choices at the start. \groupaddchoice{\LaTeX} \groupaddchoice{LibreOffice} \groupaddchoice{Microsoft Word} \groupaddchoice{other} % After that it is possible to add each question. \choiceline{writing letters} \choiceline{creating tables} \choiceline{typesetting equations} \end{choicegroup} \section{Freeform text fields} SDAPS will extract freeform textfields such as below as images and put these into reports. SDAPS knows whether there is writing in the box and how large it is. % This is a textbox which is at least 2cm high. It will automatically scale % to fill the page. \textbox{2cm}{Do you have any comments?} % Force a new page here \newpage \section{Tricks and Features} SDAPS can also use circular checkboxes if you prefere. Or you can use the {\ttfamily multicol} package to create multi-column layouts as is done below. % Set checkbox style to be circular \def\checkboxstyle{ellipse} \begin{multicols}{2} \singlemark{This is a range question}{lower bound}{upper bound}% % Note that we need the % at the end of the last line to prevent % LaTeX from inserting too much whitespace. \label{somelabel} As you can see, this is a multi-column layout. The {\ttfamily markgroup} and {\ttfamily choicegroup} environments may be a bit tight in this mode. Lets put some more questions here, just because we can. \begin{choicequestion}[cols=1]{A choice question!} \choiceitem{first choice} \choiceitem{second choice} \choiceitem{third choice} \choiceitemtext{1.2cm}{1}{other:} \end{choicequestion} \singlemark{Another range question}{lower bound}{upper bound} This text is closer to the question compared to question~\ref{somelabel} because it is not starting a new paragraph. \textbox{3cm}{And a freeform text field} \end{multicols} That's it for the multi-column part; it was fun while it lasted! There are some more special commands. You can draw \checkedbox{} crossed checkboxes, \filledbox{} filled or \correctedbox{} filled and crossed ones. Finally there is also the plain \checkbox{} checkbox using {\ttfamily \textbackslash{}checkbox} or the starred versions showing single choice items \checkbox*{} \checkedbox*{}. These are for decoration purposes only and do not affect further processing in any way. \textbox*{2cm}{And textboxes with a fixed height. This one is exactly 2\,cm high.} % Reset checkbox style again. \def\checkboxstyle{box} \end{questionnaire} \end{document} sdaps-1.9.8/po/0000755000175000000660000000000013611127124014013 5ustar benjaminlock00000000000000sdaps-1.9.8/po/POTFILES.in0000644000175000000660000000211113367301321015564 0ustar benjaminlock00000000000000sdaps/__init__.py sdaps/script.py sdaps/add/__init__.py sdaps/annotate/__init__.py sdaps/boxgallery/__init__.py sdaps/log.py sdaps/cmdline/add.py sdaps/cmdline/annotate.py sdaps/cmdline/boxgallery.py sdaps/cmdline/convert.py sdaps/cmdline/cover.py sdaps/cmdline/csvdata.py sdaps/cmdline/gui.py sdaps/cmdline/ids.py sdaps/cmdline/info.py sdaps/cmdline/recognize.py sdaps/cmdline/reorder.py sdaps/cmdline/report.py sdaps/cmdline/reporttex.py sdaps/cmdline/reset.py sdaps/cmdline/setup.py sdaps/cmdline/stamp.py sdaps/convert/__init__.py sdaps/cover/__init__.py sdaps/csvdata/__init__.py sdaps/csvdata/buddies.py sdaps/gui/__init__.py [type: gettext/glade] sdaps/gui/main_window.ui sdaps/gui/widget_buddies.py sdaps/image/__init__.py sdaps/utils/latex.py sdaps/utils/opencv.py sdaps/model/survey.py sdaps/recognize/buddies.py sdaps/recognize/__init__.py sdaps/reorder/__init__.py sdaps/report/answers.py sdaps/report/__init__.py sdaps/reset/__init__.py sdaps/setup/__init__.py sdaps/setup/buddies.py sdaps/stamp/__init__.py sdaps/stamp/latex.py sdaps/setuptex/__init__.py sdaps/reporttex/__init__.py sdaps-1.9.8/po/POTFILES.skip0000644000175000000660000000001213346275473016141 0ustar benjaminlock00000000000000build tex sdaps-1.9.8/po/ar.po0000644000175000000660000006475313410742232014774 0ustar benjaminlock00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:10+0100\n" "PO-Revision-Date: 2015-07-01 10:51+0200\n" "Last-Translator: Hatim Alahmadi \n" "Language-Team: Arabic \n" "Language: ar\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " "&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n" "X-Generator: Weblate 2.4-dev\n" #: ../sdaps/script.py:41 msgid "SDAPS -- Paper based survey tool." msgstr "SDAPS -- اداة ورقة الاستفتاءات الاساسية." #: ../sdaps/script.py:45 msgid "command list|Commands:" msgstr "قائمة الاوامر|الاوامر:" #: ../sdaps/script.py:50 msgid "project directory|The SDAPS project." msgstr "مسار المشروع|مشروع سدابس." #: ../sdaps/add/__init__.py:55 #, python-format msgid "" "Invalid input file %s. You need to specify a (multipage) monochrome TIFF as " "input." msgstr "" #: ../sdaps/add/__init__.py:67 #, python-format msgid "" "Not adding %s because it has a wrong page count (needs to be a mulitple of " "%i)." msgstr "" #: ../sdaps/boxgallery/__init__.py:108 #, python-format msgid "Rendering boxgallery for metric \"%s\"." msgstr "" #: ../sdaps/log.py:37 msgid "Warning: " msgstr "تحذير: " #: ../sdaps/log.py:41 msgid "Error: " msgstr "خطأ: " #: ../sdaps/cmdline/add.py:31 msgid "Add scanned questionnaires to the survey." msgstr "إضافة الاسئلة الممسوحة للاستفتاء." #: ../sdaps/cmdline/add.py:32 msgid "" "This command is used to add scanned images to the survey.\n" " The image data needs to be a (multipage) 300dpi monochrome TIFF file. " "You\n" " may choose not to copy the data into the project directory. In that " "case\n" " the data will be referenced using a relative path." msgstr "" #: ../sdaps/cmdline/add.py:38 msgid "Convert given files and add the result." msgstr "" #: ../sdaps/cmdline/add.py:43 msgid "" "Do a 3D-transformation after finding the corner marks. If the\n" " corner marks are not found then the image will be added as-is." msgstr "" #: ../sdaps/cmdline/add.py:49 msgid "" "Force adding the images even if the page count is wrong (only use if you " "know what you are doing)." msgstr "" #: ../sdaps/cmdline/add.py:53 msgid "Copy the files into the directory (default)." msgstr "نسخ الملفات إلى المسار (الافتراضي)." #: ../sdaps/cmdline/add.py:58 msgid "Do not copy the files into the directory." msgstr "لا تنسخ الملفات إلى المسار." #: ../sdaps/cmdline/add.py:62 msgid "" "Images contain a duplex scan of a simplex questionnaire (default: simplex " "scan)." msgstr "" #: ../sdaps/cmdline/add.py:68 ../sdaps/cmdline/convert.py:48 msgid "A number of TIFF image files." msgstr "عدد ملفات صور TIFF ." #: ../sdaps/cmdline/add.py:94 msgid "The --no-copy option is not compatible with --convert!" msgstr "" #: ../sdaps/cmdline/add.py:103 msgid "Converting input files into a single temporary file." msgstr "" #: ../sdaps/cmdline/add.py:115 msgid "" "The page count of the created temporary file does not work with this survey." msgstr "" #: ../sdaps/cmdline/add.py:120 msgid "Running the conversion failed." msgstr "" #: ../sdaps/cmdline/add.py:126 #, python-format msgid "Processing %s" msgstr "" #: ../sdaps/cmdline/add.py:130 ../sdaps/reset/__init__.py:33 msgid "Done" msgstr "تم" #: ../sdaps/cmdline/annotate.py:28 msgid "Annotate the questionnaire and show the recognized positions." msgstr "" #: ../sdaps/cmdline/annotate.py:29 msgid "" "This command is mainly a debug utility. It creates an\n" " annotated version of the questionnaire, with the information that SDAPS\n" " knows about it overlayed on top." msgstr "" #: ../sdaps/cmdline/boxgallery.py:31 msgid "Create PDFs with boxes sorted by the detection heuristics." msgstr "" #: ../sdaps/cmdline/boxgallery.py:32 msgid "" "SDAPS uses multiple heuristics to detect determine the\n" " state of checkboxes. There is a list for each heuristic giving the " "expected\n" " state and the quality of the value (see defs.py). Using this command a " "PDF\n" " will be created for each of the heuristics so that one can adjust the\n" " values." msgstr "" #: ../sdaps/cmdline/boxgallery.py:40 msgid "" "Reruns part of the recognition process and retrieves debug images from this " "step." msgstr "" #: ../sdaps/cmdline/convert.py:30 msgid "Convert a set of images to the correct image format." msgstr "" #: ../sdaps/cmdline/convert.py:31 msgid "" "This command can be used if you scanned files in something\n" " other than the expected monochrome TIFF mode. All given files will\n" " be loaded, converted to monochrome and stored in a multipage 1bpp\n" " TIFF file. Optionally, you can select \"3D transformation\"\\ ,which " "may facilitate\n" " working with photos of questionnaires instead of scans." msgstr "" #: ../sdaps/cmdline/convert.py:38 msgid "" "Do a 3D-transformation after finding the corner marks.\n" " If they are not found, the image will be processed as-is." msgstr "" #: ../sdaps/cmdline/convert.py:44 msgid "The location of the output file." msgstr "" #: ../sdaps/cmdline/convert.py:57 msgid "No output filename specified!" msgstr "" #: ../sdaps/cmdline/cover.py:27 msgid "Create a cover for the questionnaires." msgstr "انشاء غلاف للاسئلة." #: ../sdaps/cmdline/cover.py:28 msgid "" "This command creates a cover page for questionnaires. All\n" " the metadata of the survey will be printed on the page." msgstr "" #: ../sdaps/cmdline/cover.py:31 #, python-format msgid "Filename to store the data to (default: cover_%%i.pdf)" msgstr "" #: ../sdaps/cmdline/csvdata.py:34 msgid "Import or export data to/from CSV files." msgstr "" #: ../sdaps/cmdline/csvdata.py:35 msgid "" "Import or export data to/from a CSV file. The first line\n" " is a header which defines questionnaire_id and global_id, and a column\n" " for each checkbox and textfield. Note that the import is currently very\n" " limited, as you need to specifiy the questionnaire ID to select the " "sheet\n" " which should be updated." msgstr "" #: ../sdaps/cmdline/csvdata.py:44 msgid "Export data to CSV file." msgstr "" #: ../sdaps/cmdline/csvdata.py:46 #, python-format msgid "Filename to store the data to (default: data_%%i.csv)" msgstr "" #: ../sdaps/cmdline/csvdata.py:48 msgid "The delimiter used in the CSV file (default ',')" msgstr "" #: ../sdaps/cmdline/csvdata.py:52 ../sdaps/cmdline/report.py:31 #: ../sdaps/cmdline/reporttex.py:52 msgid "Filter to only export a partial dataset." msgstr "" #: ../sdaps/cmdline/csvdata.py:54 msgid "Export images of freeform fields." msgstr "" #: ../sdaps/cmdline/csvdata.py:60 #, fuzzy msgid "Export an image for each question that includes all boxes." msgstr "تصدير واستيراد معرفات الاسئلة." #: ../sdaps/cmdline/csvdata.py:66 msgid "Export the recognition quality for each checkbox." msgstr "" #: ../sdaps/cmdline/csvdata.py:74 msgid "Import data to from a CSV file." msgstr "" #: ../sdaps/cmdline/csvdata.py:76 msgid "The file to import." msgstr "" #: ../sdaps/cmdline/gui.py:28 msgid "Launch a GUI. You can view and alter the (recognized) answers with it." msgstr "" #: ../sdaps/cmdline/gui.py:29 msgid "" "This command launches a graphical user interface that can\n" " be used to correct answers. You need to run \"recognize\" before using " "it.\n" " " msgstr "" #: ../sdaps/cmdline/gui.py:34 msgid "Filter to only show a partial dataset." msgstr "" #: ../sdaps/cmdline/ids.py:29 msgid "Export and import questionnaire IDs." msgstr "تصدير واستيراد معرفات الاسئلة." #: ../sdaps/cmdline/ids.py:30 msgid "" "This command can be used to import and export questionnaire\n" " IDs. It only makes sense in projects where such an ID is printed on the\n" " questionnaire. Note that you can also add IDs by using the stamp " "command,\n" " which will give you the PDF at the same time." msgstr "" #: ../sdaps/cmdline/ids.py:35 #, python-format msgid "Filename to store the data to (default: ids_%%i)" msgstr "" #: ../sdaps/cmdline/ids.py:38 msgid "Add IDs to the internal list from the specified file." msgstr "" #: ../sdaps/cmdline/info.py:28 msgid "Display and modify metadata of project." msgstr "" #: ../sdaps/cmdline/info.py:29 msgid "" "This command lets you modify the metadata of the SDAPS\n" " project. You can modify, add and remove arbitrary keys that will be " "printed\n" " on the report. The only key that always exist is \"title\".\n" " If no key is given then a list of defined keys is printed." msgstr "" #: ../sdaps/cmdline/info.py:36 msgid "Delete the key and value pair." msgstr "" #: ../sdaps/cmdline/info.py:40 msgid "The key to display or modify." msgstr "" #: ../sdaps/cmdline/info.py:44 msgid "Set the given key to this value." msgstr "" #: ../sdaps/cmdline/info.py:69 msgid "Existing fields:\n" msgstr "" #: ../sdaps/cmdline/recognize.py:28 msgid "Run the optical mark recognition." msgstr "" #: ../sdaps/cmdline/recognize.py:29 msgid "" "Iterates over all images and runs the optical mark\n" " recognition. It will reevaluate sheets even if \"recognize\" has " "already\n" " run or manual changes were made." msgstr "" #: ../sdaps/cmdline/recognize.py:34 msgid "" "Only identify the page properties, but don't recognize the checkbox states." msgstr "" #: ../sdaps/cmdline/recognize.py:39 msgid "" "Rerun the recognition for all pages. The default is to skip all pages that " "were recognized or verified already." msgstr "" #: ../sdaps/cmdline/reorder.py:26 #, fuzzy msgid "Reorder pages according to questionnaire ID." msgstr "تصدير واستيراد معرفات الاسئلة." #: ../sdaps/cmdline/reorder.py:27 msgid "" "This command reorders all pages according to the already\n" " recognized questionnaire ID. To use it add all the files to the " "project,\n" " then run a partial recognition using \"recognize --identify\". After " "this\n" " you have to run this command to reorder the data for the real " "recognition.\n" " " msgstr "" #: ../sdaps/cmdline/report.py:26 msgid "Create a PDF report." msgstr "انشاء تقرير اكروبات." #: ../sdaps/cmdline/report.py:27 msgid "" "This command creates a PDF report using reportlab that\n" " contains statistics and if selected the freeform fields." msgstr "" #: ../sdaps/cmdline/report.py:33 msgid "Create a filtered report for every checkbox." msgstr "" #: ../sdaps/cmdline/report.py:36 msgid "Short format (without freeform text fields)." msgstr "" #: ../sdaps/cmdline/report.py:41 msgid "Detailed output. (default)" msgstr "" #: ../sdaps/cmdline/report.py:47 ../sdaps/cmdline/reporttex.py:30 msgid "" "Do not include original images in the report. This is useful if there are " "privacy concerns." msgstr "" #: ../sdaps/cmdline/report.py:52 ../sdaps/cmdline/reporttex.py:35 msgid "Do not use substitutions instead of images." msgstr "" #: ../sdaps/cmdline/report.py:58 ../sdaps/cmdline/reporttex.py:46 msgid "The paper size used for the output (default: locale dependent)" msgstr "" #: ../sdaps/cmdline/report.py:61 ../sdaps/cmdline/reporttex.py:49 #, python-format msgid "Filename to store the data to (default: report_%%i.pdf)" msgstr "" #: ../sdaps/cmdline/reporttex.py:26 msgid "Create a PDF report using LaTeX." msgstr "انشاء تقرير أكروبات باستخدام لتيك." #: ../sdaps/cmdline/reporttex.py:27 msgid "" "This command creates a PDF report using LaTeX that\n" " contains statistics and freeform fields." msgstr "" #: ../sdaps/cmdline/reporttex.py:41 msgid "Save the generated TeX files instead of the final PDF." msgstr "" #: ../sdaps/cmdline/reset.py:26 msgid "Reset project into original state" msgstr "" #: ../sdaps/cmdline/reset.py:27 msgid "" "This command does a full reset of the project. All data\n" " will be discarded and only the empty project is left.\n" " " msgstr "" #: ../sdaps/cmdline/setup.py:27 msgid "Create a new survey using a LaTeX document." msgstr "انشاء استفتاء جديد باستخدام مستند لتيك." #: ../sdaps/cmdline/setup.py:28 msgid "" "Create a new survey from a LaTeX document. You need to\n" " be using the SDAPS class. All the metadata and options for the project\n" " can be set inside the LaTeX document." msgstr "" #: ../sdaps/cmdline/setup.py:33 msgid "The LaTeX Document" msgstr "مستند لتيك" #: ../sdaps/cmdline/setup.py:35 msgid "" "Additional files that are required by the LaTeX document and need to be " "copied into the project directory." msgstr "" #: ../sdaps/cmdline/setup.py:39 msgid "Additional questions that are not part of the questionnaire." msgstr "" #: ../sdaps/cmdline/stamp.py:26 msgid "Add marks for automatic processing." msgstr "" #: ../sdaps/cmdline/stamp.py:27 msgid "" "This command creates the printable document. Depending on\n" " the projects setting you are required to specifiy a source for " "questionnaire\n" " IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:33 msgid "" "If using questionnaire IDs, create N questionnaires with randomized IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:36 msgid "" "If using questionnaire IDs, create questionnaires from the IDs read from the " "specified file." msgstr "" #: ../sdaps/cmdline/stamp.py:39 msgid "If using questionnaire IDs, create questionnaires for all stored IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:42 #, python-format msgid "Filename to store the data to (default: stamp_%%i.pdf)" msgstr "" #: ../sdaps/convert/__init__.py:37 #, python-format msgid "Could not apply 3D-transformation to image '%s', page %i!" msgstr "" #: ../sdaps/cover/__init__.py:40 #, fuzzy msgid "SDAPS questionnaire" msgstr "معرف-السؤال: %i" #: ../sdaps/csvdata/buddies.py:77 #, fuzzy, python-format msgid "Not importing unknown questionnaire ID \"%s\"" msgstr "تصدير واستيراد معرفات الاسئلة." #: ../sdaps/gui/__init__.py:59 msgid "" "The survey does not have any images! Please add images (and run recognize) " "before using the GUI." msgstr "" #: ../sdaps/gui/__init__.py:211 msgid "Page|Invalid" msgstr "" #: ../sdaps/gui/__init__.py:214 #, python-format msgid "Page %i" msgid_plural "Page %i" msgstr[0] "صفحة %i" msgstr[1] "صفحة %i" msgstr[2] "صفحة %i" msgstr[3] "صفحة %i" msgstr[4] "صفحة %i" msgstr[5] "صفحة %i" #: ../sdaps/gui/__init__.py:256 msgid "Copyright © 2007-2014 The SDAPS Authors" msgstr "" #: ../sdaps/gui/__init__.py:258 msgid "Scripts for data acquisition with paper based surveys" msgstr "" #: ../sdaps/gui/__init__.py:259 msgid "http://sdaps.org" msgstr "" #: ../sdaps/gui/__init__.py:260 msgid "translator-credits" msgstr "" #: ../sdaps/gui/__init__.py:305 #, python-format msgid " of %i" msgstr " من %i" #: ../sdaps/gui/__init__.py:306 #, python-format msgid "Recognition Quality: %.2f" msgstr "" #: ../sdaps/gui/__init__.py:322 msgid "" "You have reached the first page of the survey. Would you like to go to the " "last page?" msgstr "" #: ../sdaps/gui/__init__.py:324 msgid "Go to last page" msgstr "" #: ../sdaps/gui/__init__.py:346 msgid "" "You have reached the last page of the survey. Would you like to go to the " "first page?" msgstr "" #: ../sdaps/gui/__init__.py:348 msgid "Go to first page" msgstr "" #: ../sdaps/gui/__init__.py:457 msgid "Close without saving" msgstr "إغلاق بدون حفظ" #: ../sdaps/gui/__init__.py:461 msgid "" "Save the project before closing?\n" "\n" "If you do not save you may loose data." msgstr "" #: ../sdaps/gui/main_window.ui.h:1 msgid "Forward" msgstr "التالي" #: ../sdaps/gui/main_window.ui.h:2 msgid "Previous" msgstr "السابق" #: ../sdaps/gui/main_window.ui.h:3 msgid "Zoom In" msgstr "تكبير" #: ../sdaps/gui/main_window.ui.h:4 msgid "Zoom Out" msgstr "تصغير" #: ../sdaps/gui/main_window.ui.h:5 msgid "SDAPS" msgstr "سدابس" #: ../sdaps/gui/main_window.ui.h:6 msgid "_File" msgstr "_ملف" #: ../sdaps/gui/main_window.ui.h:7 msgid "_View" msgstr "_عرض" #: ../sdaps/gui/main_window.ui.h:8 msgid "_Help" msgstr "_مساعدة" #: ../sdaps/gui/main_window.ui.h:9 msgid "Page Rotated" msgstr "دورت الصفحة" #: ../sdaps/gui/main_window.ui.h:10 msgid "Sort by Quality" msgstr "فرز حسب الجودة" #: ../sdaps/gui/main_window.ui.h:11 msgid "label" msgstr "" #: ../sdaps/gui/widget_buddies.py:56 msgid "Global Properties" msgstr "" #: ../sdaps/gui/widget_buddies.py:60 msgid "Sheet valid" msgstr "" #: ../sdaps/gui/widget_buddies.py:61 msgid "Sheet Verified" msgstr "" #: ../sdaps/gui/widget_buddies.py:62 #, fuzzy msgid "Page Verified" msgstr "صفحة %i" #: ../sdaps/gui/widget_buddies.py:63 msgid "Empty" msgstr "" #: ../sdaps/gui/widget_buddies.py:75 ../sdaps/gui/widget_buddies.py:105 msgid "Questionnaire ID: " msgstr "معرف السؤال: " #: ../sdaps/image/__init__.py:47 msgid "" "It appears you have not build the C extension. Please run \"./setup.py build" "\" in the toplevel directory." msgstr "" #: ../sdaps/utils/latex.py:29 msgid "" "The latex character map is missing! Please build it using the supplied tool " "(create-latexmap.py)." msgstr "" #: ../sdaps/utils/latex.py:69 msgid "" "Generated string for LaTeX contains unicode characters. This may not work " "correctly and could mean the LaTeX character map needs to be updated." msgstr "" #: ../sdaps/utils/opencv.py:35 msgid "Cannot convert PDF files as poppler is not installed or usable!" msgstr "" #: ../sdaps/utils/opencv.py:44 msgid "File does not exist" msgstr "" #. The old code used to first filter, and then run; but that is #. a bit ineffective in a way #: ../sdaps/model/survey.py:386 #, python-format msgid "%i sheet" msgid_plural "%i sheets" msgstr[0] "" msgstr[1] "" #: ../sdaps/model/survey.py:402 #, python-format msgid "Processed %i of %i sheets, took %f seconds" msgstr "" #: ../sdaps/model/survey.py:449 msgid "" "A questionnaire that is printed in duplex needs an even amount of pages!" msgstr "" #: ../sdaps/model/survey.py:453 msgid "" "The 'classic' style only supports a maximum of six pages! Use the 'code128' " "style if you require more pages." msgstr "" #: ../sdaps/model/survey.py:466 msgid "IDs need to be integers in \"classic\" style!" msgstr "" #: ../sdaps/model/survey.py:472 #, python-format msgid "Invalid character %s in questionnaire ID \"%s\" in \"code128\" style!" msgstr "" #: ../sdaps/model/survey.py:476 msgid "" "SDAPS cannot draw a questionnaire ID with the \"custom\" style. Do this " "yourself somehow!" msgstr "" #. in simplex mode every page will have a matrix; it might be a None #. matrix though #: ../sdaps/recognize/buddies.py:71 #, python-format msgid "%s, %i: Matrix not recognized." msgstr "" #: ../sdaps/recognize/buddies.py:80 #, python-format msgid "%s, %i: Rotation not found." msgstr "" #. Copy the rotation over (if required) and print warning if the rotation is unknown #: ../sdaps/recognize/buddies.py:84 #, python-format msgid "Neither %s, %i or %s, %i has a known rotation!" msgstr "" #: ../sdaps/recognize/buddies.py:96 #, python-format msgid "%s, %i: Matrix not recognized (again)." msgstr "" #: ../sdaps/recognize/buddies.py:110 #, python-format msgid "%s, %i: Could not get page number." msgstr "" #. Whoa, that should not happen. #: ../sdaps/recognize/buddies.py:130 #, python-format msgid "Neither %s, %i or %s, %i has a known page number!" msgstr "" #. We don't touch the ignore flag in this case #. Simply print a message as this should *never* happen #: ../sdaps/recognize/buddies.py:141 #, python-format msgid "" "Got a simplex document where two adjacent pages had a known page number. " "This should never happen as even simplex scans are converted to duplex by " "inserting dummy pages. Maybe you did a simplex scan but added it in duplex " "mode? The pages in question are %s, %i and %s, %i." msgstr "" #: ../sdaps/recognize/buddies.py:158 #, python-format msgid "Images %s, %i and %s, %i do not have consecutive page numbers!" msgstr "" #: ../sdaps/recognize/buddies.py:174 #, python-format msgid "No page number for page %s, %i exists." msgstr "" #: ../sdaps/recognize/buddies.py:179 #, python-format msgid "Page number for page %s, %i already used by another image." msgstr "" #: ../sdaps/recognize/buddies.py:185 #, python-format msgid "Page number %i for page %s, %i is out of range." msgstr "" #: ../sdaps/recognize/buddies.py:202 #, python-format msgid "%s, %i: Could not read survey ID, but should be able to." msgstr "" #: ../sdaps/recognize/buddies.py:206 #, python-format msgid "Could not read survey ID of either %s, %i or %s, %i!" msgstr "" #. Broken survey ID ... #: ../sdaps/recognize/buddies.py:213 #, python-format msgid "Got a wrong survey ID (%s, %i)! It is %s, but should be %i." msgstr "" #: ../sdaps/recognize/buddies.py:235 #, python-format msgid "%s, %i: Could not read questionnaire ID, but should be able to." msgstr "" #: ../sdaps/recognize/buddies.py:241 #, python-format msgid "Could not read questionnaire ID of either %s, %i or %s, %i!" msgstr "" #: ../sdaps/recognize/buddies.py:271 msgid "" "Got different IDs on different pages for at least one sheet! Do *NOT* try to " "use filters with this survey! You have to run a \"reorder\" step for this to " "work properly!" msgstr "" #: ../sdaps/recognize/buddies.py:326 msgid "No style buddy loaded. This needs to be done for the \"custom\" style!" msgstr "" #: ../sdaps/report/answers.py:188 #, python-format msgid "Answers: %i" msgstr "الاجابات: %i" #: ../sdaps/report/answers.py:190 #, python-format msgid "Mean: %.2f" msgstr "المتوسط: %.2f" #: ../sdaps/report/answers.py:192 #, python-format msgid "Standard Deviation: %.2f" msgstr "" #: ../sdaps/report/__init__.py:75 ../sdaps/reporttex/__init__.py:140 msgid "Turned in Questionnaires" msgstr "" #: ../sdaps/report/__init__.py:92 ../sdaps/reporttex/__init__.py:139 msgid "sdaps report" msgstr "تقرير سدابس" #: ../sdaps/reset/__init__.py:29 msgid "Removing stored data..." msgstr "" #: ../sdaps/setup/buddies.py:62 #, python-format msgid "Head %(l0)i got no title." msgstr "" #: ../sdaps/setup/buddies.py:74 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no question." msgstr "" #: ../sdaps/setup/buddies.py:114 #, python-format msgid "Error in question \"%s\"" msgstr "" #: ../sdaps/setup/buddies.py:118 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no boxes." msgstr "" #: ../sdaps/setup/buddies.py:167 #, python-format msgid "%(class)s %(l0)i.%(l1)i lower box out of range." msgstr "" #: ../sdaps/setup/buddies.py:172 #, python-format msgid "%(class)s %(l0)i.%(l1)i upper box out of range." msgstr "" #: ../sdaps/setup/buddies.py:177 #, python-format msgid "%(class)s %(l0)i.%(l1)i lower box not before upper box." msgstr "" #: ../sdaps/setup/buddies.py:213 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly two answers." msgstr "" #: ../sdaps/setup/buddies.py:234 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly one box." msgstr "" #: ../sdaps/stamp/__init__.py:38 msgid "" "You may not specify the number of sheets for this survey. All questionnaires " "will be identical as the survey has been configured to not use questionnaire " "IDs for each sheet." msgstr "" #: ../sdaps/stamp/__init__.py:76 msgid "" "This survey has been configured to use questionnaire IDs. Each questionnaire " "will be unique. You need to use on of the options to add new IDs or use the " "existing ones." msgstr "" #: ../sdaps/stamp/latex.py:18 msgid "" "There should be no need to stamp a SDAPS Project that uses LaTeX and does " "not have different questionnaire IDs printed on each sheet.\n" "I am going to do so anyways." msgstr "" #: ../sdaps/stamp/latex.py:26 #, python-format msgid "Running %s now twice to generate the stamped questionnaire." msgstr "" #: ../sdaps/stamp/latex.py:30 ../sdaps/setuptex/__init__.py:107 #: ../sdaps/setuptex/__init__.py:148 ../sdaps/reporttex/__init__.py:162 #, python-format msgid "Error running \"%s\" to compile the LaTeX file." msgstr "" #: ../sdaps/stamp/latex.py:36 #, python-format msgid "" "An error occured during creation of the report. Temporary files left in '%s'." msgstr "" #: ../sdaps/setuptex/__init__.py:46 msgid "The survey directory already exists." msgstr "مسار الاستفتاء موجود مسبقا." #: ../sdaps/setuptex/__init__.py:51 #, python-format msgid "Unknown file type (%s). questionnaire_tex should be of type text/x-tex." msgstr "" #: ../sdaps/setuptex/__init__.py:52 msgid "Will keep going, but expect failure!" msgstr "" #: ../sdaps/setuptex/__init__.py:57 #, python-format msgid "Unknown file type (%s). additionalqobjects should be text/plain." msgstr "" #: ../sdaps/setuptex/__init__.py:103 ../sdaps/setuptex/__init__.py:143 #, python-format msgid "Running %s now twice to generate the questionnaire." msgstr "" #: ../sdaps/setuptex/__init__.py:122 msgid "Caught an Exception while parsing the SDAPS file. The current state is:" msgstr "" #: ../sdaps/setuptex/__init__.py:136 msgid "" "Some combination of options and project properties do not work. Aborted " "Setup." msgstr "" #: ../sdaps/setuptex/__init__.py:162 msgid "" "An error occured in the setup routine. The survey directory still exists. " "You can for example check the questionnaire.log file for LaTeX compile " "errors." msgstr "" #: ../sdaps/reporttex/__init__.py:107 msgid "author|Unknown" msgstr "المؤلف|غير معروف" #: ../sdaps/reporttex/__init__.py:138 msgid "tex language|english" msgstr "لغة لتيك|الانجليزية" #: ../sdaps/reporttex/__init__.py:155 #, python-format msgid "The TeX project with the report data is located at '%s'." msgstr "" #: ../sdaps/reporttex/__init__.py:158 #, python-format msgid "Running %s now twice to generate the report." msgstr "" #: ../sdaps/reporttex/__init__.py:168 #, python-format msgid "An occured during creation of the report. Temporary files left in '%s'." msgstr "" #~ msgid "Create a new survey using an ODT document." #~ msgstr "انشاء استفتاء جديد باستخدام مستند odt ." #~ msgid "The ODT Document" #~ msgstr "مستند odt" #~ msgid "Enable printing of the questionnaire ID." #~ msgstr "تفعيل طباعة معرفات الاسئلة." #~ msgid "Survey-ID: %i" #~ msgstr "معرف-الاستفتاء: %i" #~ msgid "Questionnaire-ID: %i" #~ msgstr "معرف-السؤال: %i" #, fuzzy #~ msgid "PDFtk: Splitting the questionnaire for marking." #~ msgstr "تفعيل طباعة معرفات الاسئلة." sdaps-1.9.8/po/de.po0000644000175000000660000013145013417361752014762 0ustar benjaminlock00000000000000# # Benjamin Berg , 2011, 2012, 2013, 2014, 2015. # msgid "" msgstr "" "Project-Id-Version: SDAPS 0.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:10+0100\n" "PO-Revision-Date: 2019-01-14 16:21+0000\n" "Last-Translator: Martin Gwerder \n" "Language-Team: German " "\n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 3.4-dev\n" "X-Poedit-Language: German\n" "X-Poedit-Country: GERMANY\n" "X-Poedit-SourceCharset: utf-8\n" #: ../sdaps/script.py:41 msgid "SDAPS -- Paper based survey tool." msgstr "SDAPS -- Werkzeug für Umfragen mit Papier-Fragebögen." #: ../sdaps/script.py:45 msgid "command list|Commands:" msgstr "Kommandos:" #: ../sdaps/script.py:50 msgid "project directory|The SDAPS project." msgstr "Das SDAPS Projekt." #: ../sdaps/add/__init__.py:55 #, python-format msgid "" "Invalid input file %s. You need to specify a (multipage) monochrome TIFF as " "input." msgstr "" "Ungültige Eingabedatei %s. Ein (mehrseitiges) monochromes TIFF-Bild muss " "angegeben werden." #: ../sdaps/add/__init__.py:67 #, python-format msgid "" "Not adding %s because it has a wrong page count (needs to be a mulitple of " "%i)." msgstr "" "Füge Bild %s nicht hinzu, da die Anzahl der Seiten falsch ist (muss ein " "Vielfaches von %i sein)." #: ../sdaps/boxgallery/__init__.py:108 #, python-format msgid "Rendering boxgallery for metric \"%s\"." msgstr "Erstelle Überblick über die Boxen sortiert nach der Metrik \"%s\"." #: ../sdaps/log.py:37 msgid "Warning: " msgstr "Warnung: " #: ../sdaps/log.py:41 msgid "Error: " msgstr "Fehler: " #: ../sdaps/cmdline/add.py:31 msgid "Add scanned questionnaires to the survey." msgstr "Hinzufügen von gescannten Fragebögen." #: ../sdaps/cmdline/add.py:32 msgid "" "This command is used to add scanned images to the survey.\n" " The image data needs to be a (multipage) 300dpi monochrome TIFF file. " "You\n" " may choose not to copy the data into the project directory. In that " "case\n" " the data will be referenced using a relative path." msgstr "" "Dieser Befehl wird benutzt um gescannte Bilder zu der Umfrage hinzuzufügen. " "Die Bilder müss als eine (mehrseitige) 300dpi monochromes TIFF Datei " "übergeben werden. Es ist möglich auszuwählen, dass die Datei nicht in das " "Projektverzeichniss kopiert wird. In diesem Fall wird ein zum " "Projektverzeichniss relativer Pfad gespeichert." #: ../sdaps/cmdline/add.py:38 msgid "Convert given files and add the result." msgstr "Konvertiere die angegebenen Dateien und füge sie hinzu." #: ../sdaps/cmdline/add.py:43 msgid "" "Do a 3D-transformation after finding the corner marks. If the\n" " corner marks are not found then the image will be added as-is." msgstr "" "Wende eine 3D-Transformation an, nachdem die Eckmarkierungen gefunden " "wurden. Falls keine Eckmarken gefunden wird das Bild unverändert hinzugefügt." #: ../sdaps/cmdline/add.py:49 msgid "" "Force adding the images even if the page count is wrong (only use if you " "know what you are doing)." msgstr "" "Hinzufügen der Bilder forcieren, selbst wenn die Seitenzahl nicht stimmt " "(nur in einigen Fällen sinnvoll)." #: ../sdaps/cmdline/add.py:53 msgid "Copy the files into the directory (default)." msgstr "Kopier das TIFF-Bild in das Projektverzeichniss (Standard)." #: ../sdaps/cmdline/add.py:58 msgid "Do not copy the files into the directory." msgstr "Speichere einen relativen Pfad zum Bild." #: ../sdaps/cmdline/add.py:62 msgid "" "Images contain a duplex scan of a simplex questionnaire (default: simplex " "scan)." msgstr "" "Die Bilder sind ein duplex Scan eines simplex Fragebogens (Standard: simplex " "Scan)." #: ../sdaps/cmdline/add.py:68 ../sdaps/cmdline/convert.py:48 msgid "A number of TIFF image files." msgstr "Ein oder mehere TIFF Dateien." #: ../sdaps/cmdline/add.py:94 msgid "The --no-copy option is not compatible with --convert!" msgstr "" "Die Optionen --no-copy und --convert können nicht gleichzeitig verwendet " "werden!" #: ../sdaps/cmdline/add.py:103 msgid "Converting input files into a single temporary file." msgstr "Konvertiere die Eingabedateien in eine gemeinsame temporäre Datei." #: ../sdaps/cmdline/add.py:115 msgid "" "The page count of the created temporary file does not work with this survey." msgstr "" "Die Seitenzahl der erstellten temporären Datei passt nicht zur Umfrage." #: ../sdaps/cmdline/add.py:120 msgid "Running the conversion failed." msgstr "Die Konvertierung ist fehlgeschlagen." #: ../sdaps/cmdline/add.py:126 #, python-format msgid "Processing %s" msgstr "Beartbeite %s" #: ../sdaps/cmdline/add.py:130 ../sdaps/reset/__init__.py:33 msgid "Done" msgstr "Fertig" #: ../sdaps/cmdline/annotate.py:28 msgid "Annotate the questionnaire and show the recognized positions." msgstr "" "Vermerkt den Fragebogen mit Anmerkungen zu den erkannten Positionen und " "Fragen." #: ../sdaps/cmdline/annotate.py:29 msgid "" "This command is mainly a debug utility. It creates an\n" " annotated version of the questionnaire, with the information that SDAPS\n" " knows about it overlayed on top." msgstr "" "Dieser Befehl ist Hauptsächlich als Werkzeug zur Fehlerkorrektur gedacht. " "Es\n" "versieht den Fragebogen mit Anmerkungen. Damit ist es möglich die von SDAPS\n" "erkannten Informationen zu überprüfen." #: ../sdaps/cmdline/boxgallery.py:31 msgid "Create PDFs with boxes sorted by the detection heuristics." msgstr "Erstellt ein PDF mit den Kästchen um die Heuristiken zu bewerten." #: ../sdaps/cmdline/boxgallery.py:32 msgid "" "SDAPS uses multiple heuristics to detect determine the\n" " state of checkboxes. There is a list for each heuristic giving the " "expected\n" " state and the quality of the value (see defs.py). Using this command a " "PDF\n" " will be created for each of the heuristics so that one can adjust the\n" " values." msgstr "" "SDAPS benutzt mehrere Heuristiken um den Status der Ankreuzfelder zu " "erkennen. Diese\n" "werden über eine Liste (siehe defs.py) einem Zustand und einer Qualität " "zugeordner. Mit\n" "hilfe von diesem Kommando können PDFs erstellt werden um die Heuristiken zu " "bewerten und\n" "die Zuordnung anzupassen." #: ../sdaps/cmdline/boxgallery.py:40 msgid "" "Reruns part of the recognition process and retrieves debug images from this " "step." msgstr "" "Führt den Erkenner noch einmal aus, und speichert zusätzliche Bilder zur " "Fehlersuche." #: ../sdaps/cmdline/convert.py:30 msgid "Convert a set of images to the correct image format." msgstr "Konvertiert einen Satz von Bildern in das passende Format." #: ../sdaps/cmdline/convert.py:31 msgid "" "This command can be used if you scanned files in something\n" " other than the expected monochrome TIFF mode. All given files will\n" " be loaded, converted to monochrome and stored in a multipage 1bpp\n" " TIFF file. Optionally, you can select \"3D transformation\"\\ ,which " "may facilitate\n" " working with photos of questionnaires instead of scans." msgstr "" "Dieser Befehl kann angewendet werden, falls die Bilder nicht als monochromes " "TIFF gespeichert wurden. Alle angegebenen Dateien werden geladen, " "konvertiert und als mehrseitiges TIFF mit einem Bit Farbtiefe gespeichert. " "Optional kann eine 3D-Transformation angewendet werden. Dadurch können auch " "Fotos anstelle von Scans verarbeitet werden." #: ../sdaps/cmdline/convert.py:38 msgid "" "Do a 3D-transformation after finding the corner marks.\n" " If they are not found, the image will be processed as-is." msgstr "" "Wende eine 3D-Transformation an, nachdem die Eckmarkierungen gefunden " "wurden. Falls keine Eckmarken gefunden werden, wird das Bild unverändert " "hinzugefügt." #: ../sdaps/cmdline/convert.py:44 msgid "The location of the output file." msgstr "Speicherort der Ausgabedatei." #: ../sdaps/cmdline/convert.py:57 msgid "No output filename specified!" msgstr "Ausgabedatei nicht angegeben!" #: ../sdaps/cmdline/cover.py:27 msgid "Create a cover for the questionnaires." msgstr "Erstellt ein Deckblatt für die Fragebögen." #: ../sdaps/cmdline/cover.py:28 msgid "" "This command creates a cover page for questionnaires. All\n" " the metadata of the survey will be printed on the page." msgstr "" "Dieses Kommando erstellt ein Deckblatt für die Fragebögen. Dies ist\n" "eine Zusammenfassung der Metainformationen zu der Umfrage." #: ../sdaps/cmdline/cover.py:31 #, python-format msgid "Filename to store the data to (default: cover_%%i.pdf)" msgstr "Ausgabedatei (Standard: cover_%%i.pdf)" #: ../sdaps/cmdline/csvdata.py:34 msgid "Import or export data to/from CSV files." msgstr "Importieren oder exportieren von Daten im CSV Format." #: ../sdaps/cmdline/csvdata.py:35 msgid "" "Import or export data to/from a CSV file. The first line\n" " is a header which defines questionnaire_id and global_id, and a column\n" " for each checkbox and textfield. Note that the import is currently very\n" " limited, as you need to specifiy the questionnaire ID to select the " "sheet\n" " which should be updated." msgstr "" "Dieser Befehl ermöglicht den Import und Export der Daten im CSV Format. " "Dabei\n" "ist die erste Zeile eine Kopfzeile, die angibt, welche Werte in der Spalte\n" "gespeichert werden. Der Import kann derzeit nur im Zusammenhang mit der " "Fragebogen-ID\n" "benutzt werden." #: ../sdaps/cmdline/csvdata.py:44 msgid "Export data to CSV file." msgstr "Daten im CSV Format exportieren." #: ../sdaps/cmdline/csvdata.py:46 #, python-format msgid "Filename to store the data to (default: data_%%i.csv)" msgstr "Dateiname für die CSV Datei (Standard: data_%%i.csv)" #: ../sdaps/cmdline/csvdata.py:48 msgid "The delimiter used in the CSV file (default ',')" msgstr "Trennzeichen in der CSV Datei (Standard: ',')" #: ../sdaps/cmdline/csvdata.py:52 ../sdaps/cmdline/report.py:31 #: ../sdaps/cmdline/reporttex.py:52 msgid "Filter to only export a partial dataset." msgstr "Filter um nur eine Teilmenge der Daten zu exportieren." #: ../sdaps/cmdline/csvdata.py:54 msgid "Export images of freeform fields." msgstr "Bilder von Freitextfeldern exportieren." #: ../sdaps/cmdline/csvdata.py:60 msgid "Export an image for each question that includes all boxes." msgstr "Exprtiert ein Bild für jede Frage mit allen Antwortfeldern." #: ../sdaps/cmdline/csvdata.py:66 msgid "Export the recognition quality for each checkbox." msgstr "Exportiere den Qualitätswert für die Erkennung jeders Ankreuzfeldes." #: ../sdaps/cmdline/csvdata.py:74 msgid "Import data to from a CSV file." msgstr "Daten aus einer CSV Datei importieren." #: ../sdaps/cmdline/csvdata.py:76 msgid "The file to import." msgstr "Die zu importierende Datei." #: ../sdaps/cmdline/gui.py:28 msgid "Launch a GUI. You can view and alter the (recognized) answers with it." msgstr "" "Startet eine grafische Oberfläche. Sie können mit der Oberfläche die bereits " "erkannten (recognize) Antworten anzeigen und ändern." #: ../sdaps/cmdline/gui.py:29 msgid "" "This command launches a graphical user interface that can\n" " be used to correct answers. You need to run \"recognize\" before using " "it.\n" " " msgstr "" "Dieser Befehl startet eine Grafische Oberfläche, mit der es\n" "möglich ist Antworten zu korrigieren. Bevor dieser Befehl\n" "benutzt werden kann, muss das Kommando \"recognize\" schon erfolgt sein.\n" " " #: ../sdaps/cmdline/gui.py:34 msgid "Filter to only show a partial dataset." msgstr "Filter um nur einen Teil der Bögen anzuzeigen." #: ../sdaps/cmdline/ids.py:29 msgid "Export and import questionnaire IDs." msgstr "Export und Import der Fragebogen-IDs." #: ../sdaps/cmdline/ids.py:30 msgid "" "This command can be used to import and export questionnaire\n" " IDs. It only makes sense in projects where such an ID is printed on the\n" " questionnaire. Note that you can also add IDs by using the stamp " "command,\n" " which will give you the PDF at the same time." msgstr "" "Dieses Kommando kann dafür benutzt werden Fragebogen-IDs zu importieren\n" "und exportieren. Dies ist nur bei Projekten sinnvoll, bei denen auch eine\n" "eindeutige Fragebogen-ID auf den Fragebogen gedruckt wird.\n" "Es ist auch möglich Fragebogen-IDs mit dem \"stamp\" Befehl hinzuzufügen, in " "dem\n" "Fall wird gleichzeitig auch das druckbare PDF erstellt." #: ../sdaps/cmdline/ids.py:35 #, python-format msgid "Filename to store the data to (default: ids_%%i)" msgstr "Ausgabedatei (Standard: ids_%%i)" #: ../sdaps/cmdline/ids.py:38 msgid "Add IDs to the internal list from the specified file." msgstr "Fügt die IDs aus der Angegebenen Datei hinzu." #: ../sdaps/cmdline/info.py:28 msgid "Display and modify metadata of project." msgstr "Metadaten des Projekts anzeigen und verändern." #: ../sdaps/cmdline/info.py:29 msgid "" "This command lets you modify the metadata of the SDAPS\n" " project. You can modify, add and remove arbitrary keys that will be " "printed\n" " on the report. The only key that always exist is \"title\".\n" " If no key is given then a list of defined keys is printed." msgstr "" "Dieses Kommando ermöglicht es die Metadaten des SDAPS Projekts zu\n" "verändern. Es ist möglich beliebige Schlüssel zu verändern, hinzuzufügen\n" "oder zu löschen. Lediglich der Schlüssel \"title\" ist immer vorhanden.\n" "In dem Fall das kein Schlüssel angegeben wird, gibt dieses Kommando eine " "Liste\n" "aller definierten Schlüssel aus." #: ../sdaps/cmdline/info.py:36 msgid "Delete the key and value pair." msgstr "Den angegebenen Schlüssel und Wert löschen." #: ../sdaps/cmdline/info.py:40 msgid "The key to display or modify." msgstr "Der Schlüssel der angezeigt oder geändert werden soll." #: ../sdaps/cmdline/info.py:44 msgid "Set the given key to this value." msgstr "Neuer Wert für den Schlüssel." #: ../sdaps/cmdline/info.py:69 msgid "Existing fields:\n" msgstr "Definierte Felder:\n" #: ../sdaps/cmdline/recognize.py:28 msgid "Run the optical mark recognition." msgstr "Führt die automatische Erkennung durch." #: ../sdaps/cmdline/recognize.py:29 msgid "" "Iterates over all images and runs the optical mark\n" " recognition. It will reevaluate sheets even if \"recognize\" has " "already\n" " run or manual changes were made." msgstr "" "Dieser Befehl für den Erkenner für alle im Projekt vorhandenen\n" "Bilder durch. Hierbei werden auch manuelle Änderungen\n" "wieder zurückgesetzt!" #: ../sdaps/cmdline/recognize.py:34 msgid "" "Only identify the page properties, but don't recognize the checkbox states." msgstr "" "Analysiert nur die Eigenschaften der Seite, nicht jedoch die Antworten." #: ../sdaps/cmdline/recognize.py:39 msgid "" "Rerun the recognition for all pages. The default is to skip all pages that " "were recognized or verified already." msgstr "" "Erkenner über alle Seiten erneut ausführen. Ohne diese Option werden schon " "erkannte oder verifizierte Seiten übersprungen." #: ../sdaps/cmdline/reorder.py:26 msgid "Reorder pages according to questionnaire ID." msgstr "Sortiert die gescannten Seiten nach der Fragebogen-ID." #: ../sdaps/cmdline/reorder.py:27 msgid "" "This command reorders all pages according to the already\n" " recognized questionnaire ID. To use it add all the files to the " "project,\n" " then run a partial recognition using \"recognize --identify\". After " "this\n" " you have to run this command to reorder the data for the real " "recognition.\n" " " msgstr "" "Dieser Befehl ordnet alle Seiten nach ihrer Fragebogen-ID. Hierfür\n" "müssen die Fragebogen-IDs schon bekannt sein, was mit dem Befehl\n" "\"recognize --identify\" geschieht. Danach kann dieser Befehl genutzt\n" "werden, und zum Schluss ein normaler \"recognize\" Schritt um die Antworten\n" "zu erkennen." #: ../sdaps/cmdline/report.py:26 msgid "Create a PDF report." msgstr "Erstellt einen PDF Report." #: ../sdaps/cmdline/report.py:27 msgid "" "This command creates a PDF report using reportlab that\n" " contains statistics and if selected the freeform fields." msgstr "" "Dieses Kommando erstellt ein PDF Report mit Hilfe von reportlab.\n" "Dieser Report enthält Statistiken zu jeder Frage und je nach Einstellung\n" "die Freitextfelder." #: ../sdaps/cmdline/report.py:33 msgid "Create a filtered report for every checkbox." msgstr "Erstellt zu jedem Kästchen einen gefilterten Report." #: ../sdaps/cmdline/report.py:36 msgid "Short format (without freeform text fields)." msgstr "Kurzversion (ohne Freitextfelder)." #: ../sdaps/cmdline/report.py:41 msgid "Detailed output. (default)" msgstr "Langversion (Standard)" #: ../sdaps/cmdline/report.py:47 ../sdaps/cmdline/reporttex.py:30 msgid "" "Do not include original images in the report. This is useful if there are " "privacy concerns." msgstr "" "Unterdrückt die Handschriftfelder im Report. Dies sollte verwendet werden, " "wenn es Datenschutzbedenken gibt." #: ../sdaps/cmdline/report.py:52 ../sdaps/cmdline/reporttex.py:35 msgid "Do not use substitutions instead of images." msgstr "Unterdrückt die Ersetzung von Handschriftfeldern." #: ../sdaps/cmdline/report.py:58 ../sdaps/cmdline/reporttex.py:46 msgid "The paper size used for the output (default: locale dependent)" msgstr "Die Papiergröße des erstellten Dokuments (Standard: Sprachabhängig)" #: ../sdaps/cmdline/report.py:61 ../sdaps/cmdline/reporttex.py:49 #, python-format msgid "Filename to store the data to (default: report_%%i.pdf)" msgstr "Ausgabedatei (Standard: report_%%i.pdf)" #: ../sdaps/cmdline/reporttex.py:26 msgid "Create a PDF report using LaTeX." msgstr "Erstellt ein PDF Report mit LaTeX." #: ../sdaps/cmdline/reporttex.py:27 msgid "" "This command creates a PDF report using LaTeX that\n" " contains statistics and freeform fields." msgstr "" "Dieses Kommando erstellt ein PDF report mit LaTeX. Der Report enthält\n" "Statistiken und die Freitextfelder." #: ../sdaps/cmdline/reporttex.py:41 msgid "Save the generated TeX files instead of the final PDF." msgstr "Speichert die generierten TeX-Dateien anstelle des erstellten PDFs." #: ../sdaps/cmdline/reset.py:26 msgid "Reset project into original state" msgstr "Projekt in Originalzustand zurücksetzen" #: ../sdaps/cmdline/reset.py:27 msgid "" "This command does a full reset of the project. All data\n" " will be discarded and only the empty project is left.\n" " " msgstr "" "Dieser Befehl setzt das Projekt in den Originalzustand zurück. Alle " "gespeicherten Daten werden gelöscht und das nur das leere Projekt bleibt " "übrig.\n" " " #: ../sdaps/cmdline/setup.py:27 msgid "Create a new survey using a LaTeX document." msgstr "Erstellt eine neue Umfrage aus einem LaTeX Dokument." #: ../sdaps/cmdline/setup.py:28 msgid "" "Create a new survey from a LaTeX document. You need to\n" " be using the SDAPS class. All the metadata and options for the project\n" " can be set inside the LaTeX document." msgstr "" "Dieses Kommando erstellt eine neue Umfrage aus einem LaTeX Dokument. Das\n" "Dokument muss die SDAPS Klasse verwenden. Die Metadaten und andere " "einstellungen\n" "für das Projekt werden im LaTeX Dokument gesetzt." #: ../sdaps/cmdline/setup.py:33 msgid "The LaTeX Document" msgstr "Das LaTeX Dokument" #: ../sdaps/cmdline/setup.py:35 msgid "" "Additional files that are required by the LaTeX document and need to be " "copied into the project directory." msgstr "" "Zusätzliche Dateien die von dem LaTeX Dokument benötigt werden und daher in " "das Projektverzeichnis kopiert werden müssen." #: ../sdaps/cmdline/setup.py:39 msgid "Additional questions that are not part of the questionnaire." msgstr "Weitere Fragen die nicht Teil des Fragebogens sind." #: ../sdaps/cmdline/stamp.py:26 msgid "Add marks for automatic processing." msgstr "Fügt Markierungen für den Erkenner hinzu." #: ../sdaps/cmdline/stamp.py:27 msgid "" "This command creates the printable document. Depending on\n" " the projects setting you are required to specifiy a source for " "questionnaire\n" " IDs." msgstr "" "Dieses Kommando erstellt den Druckbaren Fragebogen. Je nach Einstellung\n" "muss noch eine Quelle für (eindeutige) Fragebogen-IDs mit angegeben werden." #: ../sdaps/cmdline/stamp.py:33 msgid "" "If using questionnaire IDs, create N questionnaires with randomized IDs." msgstr "" "Wenn Fragebogen-IDs genutzt werden, dann erstelle N Fragebögen mit " "zufälliger Nummer." #: ../sdaps/cmdline/stamp.py:36 msgid "" "If using questionnaire IDs, create questionnaires from the IDs read from the " "specified file." msgstr "" "Wenn Fragebogen-IDs genutzt werden, dann lese die IDs aus der angegeben " "Datei." #: ../sdaps/cmdline/stamp.py:39 msgid "If using questionnaire IDs, create questionnaires for all stored IDs." msgstr "" "Wenn Fragebogen-IDs genutzt werden, dann erstelle Fragebögen für alle schon " "gespeicherten IDs." #: ../sdaps/cmdline/stamp.py:42 #, python-format msgid "Filename to store the data to (default: stamp_%%i.pdf)" msgstr "Ausgabedatei (default: stamp_%%i.pdf)" #: ../sdaps/convert/__init__.py:37 #, python-format msgid "Could not apply 3D-transformation to image '%s', page %i!" msgstr "" "Konnte die 3D-Transformation nicht auf Bild '%s' auf Seite %i anwenden!" # #: ../sdaps/cover/__init__.py:40 msgid "SDAPS questionnaire" msgstr "SDAPS Fragebögen" #: ../sdaps/csvdata/buddies.py:77 #, python-format msgid "Not importing unknown questionnaire ID \"%s\"" msgstr "Unbekannte Fragebogen-ID \"%s\" wird nicht importiert" #: ../sdaps/gui/__init__.py:59 msgid "" "The survey does not have any images! Please add images (and run recognize) " "before using the GUI." msgstr "" "Die Umfrage enhält noch keine Bilder! Es müssen Bilder hinzugefügt und " "\"recognize\" ausgeführt werden befor die GUI benutzbar ist." #: ../sdaps/gui/__init__.py:211 msgid "Page|Invalid" msgstr "Ungültig" #: ../sdaps/gui/__init__.py:214 #, python-format msgid "Page %i" msgid_plural "Page %i" msgstr[0] "Seite %i" msgstr[1] "Seite %i" #: ../sdaps/gui/__init__.py:256 msgid "Copyright © 2007-2014 The SDAPS Authors" msgstr "Copyright © 2007-2014 The SDAPS Authors" #: ../sdaps/gui/__init__.py:258 msgid "Scripts for data acquisition with paper based surveys" msgstr "SDAPS - Scripts zum auswerten von Papier basierten Umfragen" #: ../sdaps/gui/__init__.py:259 msgid "http://sdaps.org" msgstr "http://sdaps.org" #: ../sdaps/gui/__init__.py:260 msgid "translator-credits" msgstr "Benjamin Berg" #: ../sdaps/gui/__init__.py:305 #, python-format msgid " of %i" msgstr " von %i" #: ../sdaps/gui/__init__.py:306 #, python-format msgid "Recognition Quality: %.2f" msgstr "Erkennungsqualität: %.2f" #: ../sdaps/gui/__init__.py:322 msgid "" "You have reached the first page of the survey. Would you like to go to the " "last page?" msgstr "" "Sie haben die erste Seite der Umfrage errreicht. Möchten Sie zur letzten " "Seite springen?" #: ../sdaps/gui/__init__.py:324 msgid "Go to last page" msgstr "Zur letzten Seite springen" #: ../sdaps/gui/__init__.py:346 msgid "" "You have reached the last page of the survey. Would you like to go to the " "first page?" msgstr "" "Sie haben die letzte Seite der Umfrage errreicht. Möchten Sie zur ersten " "Seite springen?" #: ../sdaps/gui/__init__.py:348 msgid "Go to first page" msgstr "Zur ersten Seite springen" #: ../sdaps/gui/__init__.py:457 msgid "Close without saving" msgstr "Beenden ohne zu Speichern" #: ../sdaps/gui/__init__.py:461 msgid "" "Save the project before closing?\n" "\n" "If you do not save you may loose data." msgstr "" "Beenden ohne zu Speichern?\n" "Wenn Sie nicht speichern, kann es zu Datenverlust kommen." #: ../sdaps/gui/main_window.ui.h:1 msgid "Forward" msgstr "Nächste Seite" #: ../sdaps/gui/main_window.ui.h:2 msgid "Previous" msgstr "Vorherige Seite" #: ../sdaps/gui/main_window.ui.h:3 msgid "Zoom In" msgstr "Vergrößern" #: ../sdaps/gui/main_window.ui.h:4 msgid "Zoom Out" msgstr "Verkleinern" #: ../sdaps/gui/main_window.ui.h:5 msgid "SDAPS" msgstr "SDAPS" #: ../sdaps/gui/main_window.ui.h:6 msgid "_File" msgstr "_Datei" #: ../sdaps/gui/main_window.ui.h:7 msgid "_View" msgstr "_Ansicht" #: ../sdaps/gui/main_window.ui.h:8 msgid "_Help" msgstr "_Hilfe" #: ../sdaps/gui/main_window.ui.h:9 msgid "Page Rotated" msgstr "Seite Gedreht" #: ../sdaps/gui/main_window.ui.h:10 msgid "Sort by Quality" msgstr "Nach Qualität sortieren" #: ../sdaps/gui/main_window.ui.h:11 msgid "label" msgstr "Sollte niemals sichtbar sein." #: ../sdaps/gui/widget_buddies.py:56 msgid "Global Properties" msgstr "Globale Eigenschaften" #: ../sdaps/gui/widget_buddies.py:60 msgid "Sheet valid" msgstr "Bogen gültig" #: ../sdaps/gui/widget_buddies.py:61 msgid "Sheet Verified" msgstr "Blatt überprüft" #: ../sdaps/gui/widget_buddies.py:62 msgid "Page Verified" msgstr "Seite überprüft" #: ../sdaps/gui/widget_buddies.py:63 msgid "Empty" msgstr "Leer" #: ../sdaps/gui/widget_buddies.py:75 ../sdaps/gui/widget_buddies.py:105 msgid "Questionnaire ID: " msgstr "Fragebogen-ID: " #: ../sdaps/image/__init__.py:47 msgid "" "It appears you have not build the C extension. Please run \"./setup.py build" "\" in the toplevel directory." msgstr "" "Die C Bibliothek steht nicht zur verfügung. Bitte führen Sie \"./setup.by " "build\" im obersten Verzeichniss aus um die Bibliothek zu bauen." #: ../sdaps/utils/latex.py:29 msgid "" "The latex character map is missing! Please build it using the supplied tool " "(create-latexmap.py)." msgstr "" "Die Latex-Zeichensatztabelle fehlt! Bitte erzeugen Sie diese mit dem " "mitgelieferten Tool (create-latexmap.py)." #: ../sdaps/utils/latex.py:69 msgid "" "Generated string for LaTeX contains unicode characters. This may not work " "correctly and could mean the LaTeX character map needs to be updated." msgstr "" "Die durch LaTeX erzeugte Zeichenkette enthält Unicode-Zeichen. Folgedessen " "wird die Darstellung möglicherweise nicht richtig funktionieren und es " "sollte die LaTeX-Zeichensatztabelle angepasst werden." #: ../sdaps/utils/opencv.py:35 msgid "Cannot convert PDF files as poppler is not installed or usable!" msgstr "" "PDF Dateien können nicht konvertiert werden, da poppler nicht gefunden wurde " "oder nicht verwendet werden kann!" #: ../sdaps/utils/opencv.py:44 msgid "File does not exist" msgstr "Datei existiert nicht" #. The old code used to first filter, and then run; but that is #. a bit ineffective in a way #: ../sdaps/model/survey.py:386 #, python-format msgid "%i sheet" msgid_plural "%i sheets" msgstr[0] "%i Bogen" msgstr[1] "%i Bögen" #: ../sdaps/model/survey.py:402 #, python-format msgid "Processed %i of %i sheets, took %f seconds" msgstr "%i von %i Blätter in %f Sekunden verarbeitet" #: ../sdaps/model/survey.py:449 msgid "" "A questionnaire that is printed in duplex needs an even amount of pages!" msgstr "" "Ein Fragebogen der doppelseitig gedruckt werden soll, muss eine gerade " "Anzahl von Seiten haben!" #: ../sdaps/model/survey.py:453 msgid "" "The 'classic' style only supports a maximum of six pages! Use the 'code128' " "style if you require more pages." msgstr "" "Der Stil 'classic' kann nur mit bis zu sechs Seiten umgehen. Für mehr Seiten " "kann der 'code128' Stil benutzt werden." #: ../sdaps/model/survey.py:466 msgid "IDs need to be integers in \"classic\" style!" msgstr "IDs müssen im \"classic\" Stil ganze Zahlen sein!" #: ../sdaps/model/survey.py:472 #, python-format msgid "Invalid character %s in questionnaire ID \"%s\" in \"code128\" style!" msgstr "Ungültiges Zeichen %s in der Fragebogen ID \"%s\" im \"code128\" Stil!" #: ../sdaps/model/survey.py:476 msgid "" "SDAPS cannot draw a questionnaire ID with the \"custom\" style. Do this " "yourself somehow!" msgstr "" "SDAPS kann im \"custom\"-Stil keine Fragebogen ID eintragen. Tun Sie das " "irgendwie selbst!" #. in simplex mode every page will have a matrix; it might be a None #. matrix though #: ../sdaps/recognize/buddies.py:71 #, python-format msgid "%s, %i: Matrix not recognized." msgstr "%s, %i: Matrix wurde nicht erkannt." #: ../sdaps/recognize/buddies.py:80 #, python-format msgid "%s, %i: Rotation not found." msgstr "%s, %i: Drehung wurde nicht erkannt." #. Copy the rotation over (if required) and print warning if the rotation is unknown #: ../sdaps/recognize/buddies.py:84 #, python-format msgid "Neither %s, %i or %s, %i has a known rotation!" msgstr "Weder %s, %i noch %s, %i hat eine bekannte Drehung!" #: ../sdaps/recognize/buddies.py:96 #, python-format msgid "%s, %i: Matrix not recognized (again)." msgstr "%s, %i: Matrix nicht erkannt (nach Drehung)." #: ../sdaps/recognize/buddies.py:110 #, python-format msgid "%s, %i: Could not get page number." msgstr "%s, %i: Seitenzahl konnte nicht gelesen werden." #. Whoa, that should not happen. #: ../sdaps/recognize/buddies.py:130 #, python-format msgid "Neither %s, %i or %s, %i has a known page number!" msgstr "Weder %s, %i noch %s, %i haben eine bekannte Seitenzahl!" #. We don't touch the ignore flag in this case #. Simply print a message as this should *never* happen #: ../sdaps/recognize/buddies.py:141 #, python-format msgid "" "Got a simplex document where two adjacent pages had a known page number. " "This should never happen as even simplex scans are converted to duplex by " "inserting dummy pages. Maybe you did a simplex scan but added it in duplex " "mode? The pages in question are %s, %i and %s, %i." msgstr "" "Simplex Dokument mit zwei benachbarten Seiten mit bekannter Seitennummer " "bearbeitet. Das dürfte nicht passieren, da simplex Scans durch einfügen von " "Dummyseiten zu Duplexdokumenten konvertiert werden. VWurde ein simplex Scan " "im Duplexmodus hinzugefügt? Es sind die Seiten %s, %i und %s, %i betroffen." #: ../sdaps/recognize/buddies.py:158 #, python-format msgid "Images %s, %i and %s, %i do not have consecutive page numbers!" msgstr "Die Bilder %s, %i und %s, %i besitzten nicht konsekutive Seitenzahlen!" #: ../sdaps/recognize/buddies.py:174 #, python-format msgid "No page number for page %s, %i exists." msgstr "Es existiert keine Seitenzahl für Seite %s, %i." #: ../sdaps/recognize/buddies.py:179 #, python-format msgid "Page number for page %s, %i already used by another image." msgstr "Seitenzahl für Seite %s, %i wurde schon einem anderen Bild zugewiesen." #: ../sdaps/recognize/buddies.py:185 #, python-format msgid "Page number %i for page %s, %i is out of range." msgstr "Seitenzahl %i für Seite %s, %i ist außerhalb des erlaubten Bereichs." #: ../sdaps/recognize/buddies.py:202 #, python-format msgid "%s, %i: Could not read survey ID, but should be able to." msgstr "" "%s, %i: Konnte die Umfrage-ID nicht einlesen. Dies sollte aber möglich sein." #: ../sdaps/recognize/buddies.py:206 #, python-format msgid "Could not read survey ID of either %s, %i or %s, %i!" msgstr "Konnte die Umfragen-ID weder auf %s, %i noch auf %s, %i finden!" #. Broken survey ID ... #: ../sdaps/recognize/buddies.py:213 #, python-format msgid "Got a wrong survey ID (%s, %i)! It is %s, but should be %i." msgstr "" "Falsche Umfrage-ID auf Seite (%s, %i)! Die ID ist %s sollte aber %i sein." #: ../sdaps/recognize/buddies.py:235 #, python-format msgid "%s, %i: Could not read questionnaire ID, but should be able to." msgstr "" "%s, %i: Konnte die Fragebogen-ID nicht lesen. Dies sollte jedoch möglich " "sein." #: ../sdaps/recognize/buddies.py:241 #, python-format msgid "Could not read questionnaire ID of either %s, %i or %s, %i!" msgstr "Konnte die Fragebogen-ID weder auf %s, %i noch auf %s, %i finden!" #: ../sdaps/recognize/buddies.py:271 msgid "" "Got different IDs on different pages for at least one sheet! Do *NOT* try to " "use filters with this survey! You have to run a \"reorder\" step for this to " "work properly!" msgstr "" "Unterschiedliche IDs auf unterschiedlichen Seiten! Die Erkennung wird " "funktionieren, die Zuordnung der Daten ist jedoch Falsch! Falls die " "Zuordnung benötigt wird, *muss* der \"reorder\" Befehl genutzt werden, um " "die Seiten wieder korrekt zuzuordnen!" #: ../sdaps/recognize/buddies.py:326 msgid "No style buddy loaded. This needs to be done for the \"custom\" style!" msgstr "" "Keine Style-Definition geladen. Dies ist beim \"custom\" Stil erforderlich!" #: ../sdaps/report/answers.py:188 #, python-format msgid "Answers: %i" msgstr "Antworten: %i" #: ../sdaps/report/answers.py:190 #, python-format msgid "Mean: %.2f" msgstr "Mittelwert: %.2f" #: ../sdaps/report/answers.py:192 #, python-format msgid "Standard Deviation: %.2f" msgstr "Standardabweichung: %.2f" #: ../sdaps/report/__init__.py:75 ../sdaps/reporttex/__init__.py:140 msgid "Turned in Questionnaires" msgstr "Abgegebene Fragebögen" #: ../sdaps/report/__init__.py:92 ../sdaps/reporttex/__init__.py:139 msgid "sdaps report" msgstr "sdaps Report" #: ../sdaps/reset/__init__.py:29 msgid "Removing stored data..." msgstr "Lösche gespeicherte Daten ..." #: ../sdaps/setup/buddies.py:62 #, python-format msgid "Head %(l0)i got no title." msgstr "Überschrift %(l0)i hat keinen Titel." #: ../sdaps/setup/buddies.py:74 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no question." msgstr "%(class)s %(l0)i.%(l1)i hat keine Frage." #: ../sdaps/setup/buddies.py:114 #, python-format msgid "Error in question \"%s\"" msgstr "Fehler in der Frage \"%s\"" #: ../sdaps/setup/buddies.py:118 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no boxes." msgstr "%(class)s %(l0)i.%(l1)i hat keine Boxen." #: ../sdaps/setup/buddies.py:167 #, python-format msgid "%(class)s %(l0)i.%(l1)i lower box out of range." msgstr "%(class)s %(l0)i.%(l1)i untere Box ist außerhalb des Bereichs." #: ../sdaps/setup/buddies.py:172 #, python-format msgid "%(class)s %(l0)i.%(l1)i upper box out of range." msgstr "%(class)s %(l0)i.%(l1)i obere Box ist außerhalb des Bereichs." #: ../sdaps/setup/buddies.py:177 #, python-format msgid "%(class)s %(l0)i.%(l1)i lower box not before upper box." msgstr "%(class)s %(l0)i.%(l1)i untere Box ist nicht vor der oberen Box." #: ../sdaps/setup/buddies.py:213 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly two answers." msgstr "%(class)s %(l0)i.%(l1)i hat nicht exakt zwei Antworten." #: ../sdaps/setup/buddies.py:234 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly one box." msgstr "%(class)s %(l0)i.%(l1)i hat nicht exakt eine Box." #: ../sdaps/stamp/__init__.py:38 msgid "" "You may not specify the number of sheets for this survey. All questionnaires " "will be identical as the survey has been configured to not use questionnaire " "IDs for each sheet." msgstr "" "Es ist nicht möglich eine Anzahl von Fragebögen anzugeben. Alle Fragebögen " "sind gleich, da die Umfrage nicht für die Benutzung von Fragebogen-IDs für " "jeden Bogen konfiguriert wurde." #: ../sdaps/stamp/__init__.py:76 msgid "" "This survey has been configured to use questionnaire IDs. Each questionnaire " "will be unique. You need to use on of the options to add new IDs or use the " "existing ones." msgstr "" "Diese Umfrage wurde mit Fragebogen-IDs konfiguriert, weshalb all Fragebögen " "sind unterschiedlich sind. Daher muss eine der Optionen benutzt werden, um " "neue IDs hinzuzufügen, oder schon gespeicherte zu verwenden." #: ../sdaps/stamp/latex.py:18 msgid "" "There should be no need to stamp a SDAPS Project that uses LaTeX and does " "not have different questionnaire IDs printed on each sheet.\n" "I am going to do so anyways." msgstr "" "Es sollte nicht notwendig sein ein SDAPS-Projekt welches LaTeX verwendet und " "keine Fragebogen IDs hat zu stempeln.\n" "Die gewünschte Aktion wird dennoch durchgeführt." #: ../sdaps/stamp/latex.py:26 #, python-format msgid "Running %s now twice to generate the stamped questionnaire." msgstr "Führe %s zwei mal aus um den gestempelten Fragebogen zu erstellen." #: ../sdaps/stamp/latex.py:30 ../sdaps/setuptex/__init__.py:107 #: ../sdaps/setuptex/__init__.py:148 ../sdaps/reporttex/__init__.py:162 #, python-format msgid "Error running \"%s\" to compile the LaTeX file." msgstr "Fehler beim ausführen von \"%s\" um die LaTeX Datei zu kompilieren." #: ../sdaps/stamp/latex.py:36 #, python-format msgid "" "An error occured during creation of the report. Temporary files left in '%s'." msgstr "" "Es ist ein Fehler beim erstellen des Reports aufgetreten. Temporäre Dateien " "wurden in '%s' belassen." #: ../sdaps/setuptex/__init__.py:46 msgid "The survey directory already exists." msgstr "Das Umfrageverzeichniss existiert bereits." #: ../sdaps/setuptex/__init__.py:51 #, python-format msgid "Unknown file type (%s). questionnaire_tex should be of type text/x-tex." msgstr "Unbekanntes Dateiformat (%s). questionnaire_tex muss text/x-tex sein." #: ../sdaps/setuptex/__init__.py:52 msgid "Will keep going, but expect failure!" msgstr "Versuche trotzdem fortzusetzten." #: ../sdaps/setuptex/__init__.py:57 #, python-format msgid "Unknown file type (%s). additionalqobjects should be text/plain." msgstr "Unbekanntes Dateiformat (%s). additionalqobjects muss text/plain sein." #: ../sdaps/setuptex/__init__.py:103 ../sdaps/setuptex/__init__.py:143 #, python-format msgid "Running %s now twice to generate the questionnaire." msgstr "Führe %s zwei mal aus um den Fragebogen zu erstellen." #: ../sdaps/setuptex/__init__.py:122 msgid "Caught an Exception while parsing the SDAPS file. The current state is:" msgstr "" "Beim Parsen der SDAPS Datei ist ein schwerer Fehler aufgetreten. Der jetzige " "Zustand ist:" #: ../sdaps/setuptex/__init__.py:136 msgid "" "Some combination of options and project properties do not work. Aborted " "Setup." msgstr "" "Setup abgebrochen, da einige Optionen und Projekteigenschaften so nicht " "funktionieren." #: ../sdaps/setuptex/__init__.py:162 msgid "" "An error occured in the setup routine. The survey directory still exists. " "You can for example check the questionnaire.log file for LaTeX compile " "errors." msgstr "" "Es ist ein Fehler in der Setup Routine aufgetreten. Das ungültige " "Projektverzeichniss existiert noch, es ist daher möglich z.B. in die " "questionnaire.log auf LaTeX Fehler zu untersuchen." #: ../sdaps/reporttex/__init__.py:107 msgid "author|Unknown" msgstr "Unbekannt" #: ../sdaps/reporttex/__init__.py:138 msgid "tex language|english" msgstr "ngerman" #: ../sdaps/reporttex/__init__.py:155 #, python-format msgid "The TeX project with the report data is located at '%s'." msgstr "Das TeX-Projekt für den Report liegt unter '%s'." #: ../sdaps/reporttex/__init__.py:158 #, python-format msgid "Running %s now twice to generate the report." msgstr "Führe %s zwei mal aus um den Report zu erstellen." #: ../sdaps/reporttex/__init__.py:168 #, python-format msgid "An occured during creation of the report. Temporary files left in '%s'." msgstr "" "Es ist ein Fehler beim erstellen des Reports aufgetreten. Temporäre Dateien " "wurden in '%s' belassen." #~ msgid "%f seconds per sheet" #~ msgstr "%f Sekunden pro Bogen" #~ msgid "Running upgrade routines for file format version %i" #~ msgstr "Update für Dateiversion %i ausführen" #~ msgid "Create a new survey using an ODT document." #~ msgstr "Erstellt eine neue Umfrage aus einem ODT Dokument." #~ msgid "" #~ "Create a new surevey from an ODT document. The PDF export\n" #~ " of the file needs to be specified at the same time. SDAPS will " #~ "import\n" #~ " metadata (properties) and the title from the ODT document." #~ msgstr "" #~ "Dieser Befehl erstellt eine neue Umfrage aus einem ODT Dokument. Der\n" #~ "PDF export des Dokuments muss auch angegeben werden. SDAPS importiert\n" #~ "auch die Metadaten und den Titel des ODT Dokuments." #~ msgid "The ODT Document" #~ msgstr "Das ODT Dokument" #~ msgid "PDF export of the ODT document" #~ msgstr "PDF Export des ODT Dokuments" #~ msgid "Enable printing of the survey ID (default)." #~ msgstr "Ausschalten der Umfrage-ID auf den Bögen (Standard)." #~ msgid "Disable printing of the survey ID." #~ msgstr "Ausschalten der Umfrage-ID auf den Bögen." #~ msgid "Enable printing of the questionnaire ID." #~ msgstr "Einschalten der Fragebogen-ID auf den Bögen." #~ msgid "Disable printing of the questionnaire ID (default)." #~ msgstr "Ausschalten der Fragebogen-ID auf den Bögen (Standard)." #~ msgid "" #~ "Set an additional global ID for tracking. This can can only be used in " #~ "the \"code128\" style." #~ msgstr "" #~ "Setzt eine zusätzliche Globale-ID die auf die Bögen gedruckt wird. Dies " #~ "funktioniert nur im \"code128\" Stil." #~ msgid "" #~ "The stamping style to use. Should be either \"classic\" or \"code128\". " #~ "Use \"code128\" for more features." #~ msgstr "" #~ "Der Stil der zum Stempeln verwendet wird. Muss entweder \"classic\" oder " #~ "\"code128\" sein. \"code128\" hat mehr features." #~ msgid "The mode to use when detecting checkboxes." #~ msgstr "Erkennungsmodus für Ankreuzfelder." #~ msgid "" #~ "Use duplex mode (ie. only print the IDs on the back side). Requires a " #~ "mulitple of two pages." #~ msgstr "" #~ "Druckmodus auf Duplex einstellen. Die Umfrage muss eine grade Anzahl von " #~ "Seiten besitzen." #~ msgid "" #~ "Use simplex mode. IDs are printed on each page. You need a simplex scan " #~ "currently!" #~ msgstr "" #~ "Druckmodus auf Simplex einstellen. Vorsicht: Es muss derzeit auch simplex " #~ "gescannt werden!" #~ msgid "" #~ "Unknown file type (%s). questionnaire_odt should be application/vnd.oasis." #~ "opendocument.text." #~ msgstr "" #~ "Unbekanntes Dateiformat (%s). questionnaire_odt muss application/vnd." #~ "oasis.opendocument.text sein." #~ msgid "Unknown file type (%s). questionnaire_pdf should be application/pdf." #~ msgstr "" #~ "Unbekanntes Dateiformat (%s). questionnaire_pdf muss application/pdf sein." #~ msgid "" #~ "Caught an Exception while parsing the ODT file. The current state is:" #~ msgstr "" #~ "Beim Parsen der ODT Datei ist ein schwerer Fehler aufgetreten. Der " #~ "jetzige Zustand ist:" #~ msgid "" #~ "If the dependencies for the \"annotate\" command are installed, then an " #~ "annotated version will be created next to the original PDF file." #~ msgstr "" #~ "Wenn die Abhängigkeiten für den \"Anmerkungs\" Befehl installiert sind " #~ "wird die kommentierte Version zusätzlich zum original PDF erstellt." #~ msgid "" #~ "Warning: Ignoring a box (page: %i, x: %.1f, y: %.1f, width: %.1f, height: " #~ "%.1f)." #~ msgstr "" #~ "Warnung: Ignoriere Box (Seite: %i, x: %.1f, y: %.1f, width: %.1f, height: " #~ "%.1f)." #~ msgid "Survey-ID: %i" #~ msgstr "Umfrage-ID: %i" #~ msgid "Questionnaire-ID: %i" #~ msgstr "Fragebogen-ID: %i" #, fuzzy #~ msgid "You need to have either PDFtk or pyPdf installed. PDFtk is faster." #~ msgstr "" #~ "Sie müssen entweder pdtk oder pyPdf installiert haben.pdftk ist die " #~ "schnellere Metode." #~ msgid "Creating stamp PDF for %i sheet" #~ msgid_plural "Creating stamp PDF for %i sheets" #~ msgstr[0] "Erstelle gestempeltes PDF für %i Fragebogen" #~ msgstr[1] "Erstelle gestempeltes PDF für %i Fragebögen" #~ msgid "%i sheet; %f seconds per sheet" #~ msgid_plural "%i sheet; %f seconds per sheet" #~ msgstr[0] "%i Bogen; %f Sekunden pro Bogen" #~ msgstr[1] "%i Bögen; %f Sekunden pro Bogen" #, fuzzy #~ msgid "Marking using PDFtk" #~ msgstr "Stempele mit Hilfe von pdftk" #, fuzzy #~ msgid "PDFtk: Overlaying the original PDF with the markings." #~ msgstr "pdftk: Einfügen der Markierungen in das ursprüngliche PDF-Dokument." #, fuzzy #~ msgid "PDFtk: Splitting out page %d of each stack." #~ msgid_plural "PDFtk: Splitting out page %d of each stack." #~ msgstr[0] "pdftk: Extrahier die %d Seite aus dem Stempel." #~ msgstr[1] "pdftk: Extrahier die %d Seite aus dem Stempel." #, fuzzy #~ msgid "PDFtk: Splitting the questionnaire for marking." #~ msgstr "pdftk: Extrahiere die einzelnen Seiten des Fragebogens." #, fuzzy #~ msgid "PDFtk: Marking page %d of all stacks." #~ msgid_plural "PDFtk: Marking page %d of all stacks." #~ msgstr[0] "pdftk: Stempele die Seite %d." #~ msgstr[1] "pdftk: Stempele die Seite %d." #~ msgid "pdftk: Assembling everything into the final PDF." #~ msgstr "pdftk: Erstelle das fertige PDF." #, fuzzy #~ msgid "Marking using pyPdf. For faster marking, install PDFtk." #~ msgstr "Stempele mit hilfe von pyPdf. Dies würde mit pdftk schneller gehen." #~ msgid "" #~ "You selected to reference existing files, however not all files are in " #~ "the correct format. If you don't want the file to be copied into the " #~ "survey directory, you need to manually convert it first." #~ msgstr "" #~ "Es sollen bestehende Dateien referenziert werden, aber nicht alle Dateien " #~ "haben das passende Format. Wenn die Dateien nicht in das " #~ "Projektverzeichniss kopiert werden sollen müssen sie vorher konvertiert " #~ "werden." #~ msgid "" #~ "Converted image does not have correct format. This means the page count " #~ "is wrong." #~ msgstr "" #~ "Das konvertierten hat nicht das richtige Format. Die Anzahl der Seiten " #~ "ist falsch." #~ msgid "Sheet Valid (all pages)" #~ msgstr "Ausgefüllter Bogen" #~ msgid "Only generates the TeX project. This option is for debug purpose." #~ msgstr "" #~ "Generiert nur das TeX-Projekt. Diese Option ist für das Debuggen " #~ "interessant." #~ msgid "%(class)s %(l0)i.%(l1)i got not exactly five boxes." #~ msgstr "%(class)s %(l0)i.%(l1)i hat nicht exakt fünf Boxen." #~ msgid "" #~ "Found inconsistency. %s, %i and %s, %i should have the same rotation, but " #~ "don't!" #~ msgstr "" #~ "%s, %i und %s, %i sollten die gleiche Drehung haben, diese stimmt jedoch " #~ "nicht überein!" sdaps-1.9.8/po/es.po0000644000175000000660000012735713410742232015001 0ustar benjaminlock00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: SDAPS 0.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:10+0100\n" "PO-Revision-Date: 2017-12-01 16:49+0000\n" "Last-Translator: Allan Nordhøy \n" "Language-Team: Spanish \n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 2.18-dev\n" #: ../sdaps/script.py:41 msgid "SDAPS -- Paper based survey tool." msgstr "SDAPS -- Herramienta para el reconocimiento de documentos impresos." #: ../sdaps/script.py:45 msgid "command list|Commands:" msgstr "lista de comandos|Comandos:" #: ../sdaps/script.py:50 msgid "project directory|The SDAPS project." msgstr "directorio del proyecto|El proyecto SDAPS." #: ../sdaps/add/__init__.py:55 #, python-format msgid "" "Invalid input file %s. You need to specify a (multipage) monochrome TIFF as " "input." msgstr "" "Archivo de entrada inválido %s. Debe especificar un archivo (multipágina) " "monocromático TIFF como entrada." #: ../sdaps/add/__init__.py:67 #, python-format msgid "" "Not adding %s because it has a wrong page count (needs to be a mulitple of " "%i)." msgstr "" "No se ha añadido %s debido a que tiene un conteo de página incorrecto (debe " "ser múltiplo de %i)." #: ../sdaps/boxgallery/__init__.py:108 #, python-format msgid "Rendering boxgallery for metric \"%s\"." msgstr "Renderizando cajas por la métrica \"%s\"." #: ../sdaps/log.py:37 msgid "Warning: " msgstr "Advertencia: " #: ../sdaps/log.py:41 msgid "Error: " msgstr "Error: " #: ../sdaps/cmdline/add.py:31 msgid "Add scanned questionnaires to the survey." msgstr "Añade cuestionarios escaneados al reconocimiento." #: ../sdaps/cmdline/add.py:32 msgid "" "This command is used to add scanned images to the survey.\n" " The image data needs to be a (multipage) 300dpi monochrome TIFF file. " "You\n" " may choose not to copy the data into the project directory. In that " "case\n" " the data will be referenced using a relative path." msgstr "" "Este comando se emplea para añadir imágenes escaneadas al reconocimiento.\n" " La imagen de los datos debe ser un archivo (multipágina) monocromático " "TIFF de 300dpi. Usted\n" " puede elegir no copiar los datos en el directorio del proyecto. En ese " "caso\n" " se hará referencia a los datos empleando una ruta relativa." #: ../sdaps/cmdline/add.py:38 msgid "Convert given files and add the result." msgstr "Convierte los archivos especificados y añade el resultado." #: ../sdaps/cmdline/add.py:43 msgid "" "Do a 3D-transformation after finding the corner marks. If the\n" " corner marks are not found then the image will be added as-is." msgstr "" "Realiza una transformación 3D después de encontrar las marcas de esquina. Si " "no\n" " se encuentran las marcas la imagen será añadida tal cual es." #: ../sdaps/cmdline/add.py:49 msgid "" "Force adding the images even if the page count is wrong (only use if you " "know what you are doing)." msgstr "" "Fuerza el añadir las imágenes incluso si el conteo de página es incorrecto " "(empléelo únicamente si sabe lo que está haciendo." #: ../sdaps/cmdline/add.py:53 msgid "Copy the files into the directory (default)." msgstr "Copia los archivos en el directorio (por defecto)." #: ../sdaps/cmdline/add.py:58 msgid "Do not copy the files into the directory." msgstr "No copia los archivos en el directorio." #: ../sdaps/cmdline/add.py:62 msgid "" "Images contain a duplex scan of a simplex questionnaire (default: simplex " "scan)." msgstr "" "Las imágenes contienen un escaneo doble de un cuestionario sencillo (por " "defecto: escaneo sencillo)." #: ../sdaps/cmdline/add.py:68 ../sdaps/cmdline/convert.py:48 msgid "A number of TIFF image files." msgstr "Un número de archivos de imagen TIFF." #: ../sdaps/cmdline/add.py:94 msgid "The --no-copy option is not compatible with --convert!" msgstr "La opción -no-copy no es compatible con --convert!" #: ../sdaps/cmdline/add.py:103 msgid "Converting input files into a single temporary file." msgstr "Convirtiendo archivos de entrada en un único archivo temporal." #: ../sdaps/cmdline/add.py:115 msgid "" "The page count of the created temporary file does not work with this survey." msgstr "El recuento del archivo temporal creado no funciona con esta encuesta." #: ../sdaps/cmdline/add.py:120 msgid "Running the conversion failed." msgstr "Fallo al ejecutar la conversión." #: ../sdaps/cmdline/add.py:126 #, python-format msgid "Processing %s" msgstr "Procesando %s" #: ../sdaps/cmdline/add.py:130 ../sdaps/reset/__init__.py:33 msgid "Done" msgstr "Finalizado" #: ../sdaps/cmdline/annotate.py:28 msgid "Annotate the questionnaire and show the recognized positions." msgstr "Comenta el cuestionario y muestra la posiciones reconocidas." #: ../sdaps/cmdline/annotate.py:29 msgid "" "This command is mainly a debug utility. It creates an\n" " annotated version of the questionnaire, with the information that SDAPS\n" " knows about it overlayed on top." msgstr "" "Este comando es principalmente una herramienta para depuración. Crea una\n" " versión comentada del cuestionario con la información que SDAPS\n" " conoce acerca de él sobrepuesta en la parte superior." #: ../sdaps/cmdline/boxgallery.py:31 msgid "Create PDFs with boxes sorted by the detection heuristics." msgstr "" "Crear archivos PDF con casillas ordenadas por la heurística de detección." #: ../sdaps/cmdline/boxgallery.py:32 msgid "" "SDAPS uses multiple heuristics to detect determine the\n" " state of checkboxes. There is a list for each heuristic giving the " "expected\n" " state and the quality of the value (see defs.py). Using this command a " "PDF\n" " will be created for each of the heuristics so that one can adjust the\n" " values." msgstr "" "SDAPS emplea heurística múltiple para determinar el\n" " estado de las casillas de verificación. Existe una lista para cada " "heurística que proporciona\n" " el estado y la calidad del valor (ver defs.py). Empleando este comando se " "creará\n" " un archivo PDF para cada heurística de tal forma que se puedan ajustar\n" " los valores." #: ../sdaps/cmdline/boxgallery.py:40 msgid "" "Reruns part of the recognition process and retrieves debug images from this " "step." msgstr "" "Reejecuta parte del proceso de reconocimiento y recupera imágenes de " "depuración a partir de este paso." #: ../sdaps/cmdline/convert.py:30 msgid "Convert a set of images to the correct image format." msgstr "Convierte un conjunto de imágenes al formato correcto de imagen." #: ../sdaps/cmdline/convert.py:31 #, fuzzy msgid "" "This command can be used if you scanned files in something\n" " other than the expected monochrome TIFF mode. All given files will\n" " be loaded, converted to monochrome and stored in a multipage 1bpp\n" " TIFF file. Optionally, you can select \"3D transformation\"\\ ,which " "may facilitate\n" " working with photos of questionnaires instead of scans." msgstr "" "Este comando puede ser empleado si usted escaneo archivos en un modo\n" " distinto al archivo TIFF monocromático esperado. Todos los archivos " "proporcionados\n" " se cargarán, convertirán a monocromático y almacenarán en un archivo " "multipágina\n" " 1bpp TIFF. Opcionamente, usted puede seleccionar que se realice una " "transformación 3D,\n" " haciéndolo es posible trabajar con fotografías de\n" " cuestionarios en lugar de escaneos." #: ../sdaps/cmdline/convert.py:38 #, fuzzy msgid "" "Do a 3D-transformation after finding the corner marks.\n" " If they are not found, the image will be processed as-is." msgstr "" "Realiza una transformación 3D después de encontrar las marcas de esquina. Si " "no\n" " se encuentran las marcas la imagen será añadida tal cual es." #: ../sdaps/cmdline/convert.py:44 #, fuzzy msgid "The location of the output file." msgstr "Se debe proporcionar la localización del archivo de salida." #: ../sdaps/cmdline/convert.py:57 msgid "No output filename specified!" msgstr "¡No se especificó un nombre de archivo de salida!" #: ../sdaps/cmdline/cover.py:27 msgid "Create a cover for the questionnaires." msgstr "Crea una portada para los cuestionarios." #: ../sdaps/cmdline/cover.py:28 msgid "" "This command creates a cover page for questionnaires. All\n" " the metadata of the survey will be printed on the page." msgstr "" "Este comando crea una página portada para los cuestionarios. En ella\n" " se imprimirán todos los metadatos de la captura." #: ../sdaps/cmdline/cover.py:31 #, python-format msgid "Filename to store the data to (default: cover_%%i.pdf)" msgstr "" "Nombre del archivo para almacenar los datos (por defecto: cover_%%i.pdf)" #: ../sdaps/cmdline/csvdata.py:34 msgid "Import or export data to/from CSV files." msgstr "Importar o exportar datos a/desde archivos CSV." #: ../sdaps/cmdline/csvdata.py:35 msgid "" "Import or export data to/from a CSV file. The first line\n" " is a header which defines questionnaire_id and global_id, and a column\n" " for each checkbox and textfield. Note that the import is currently very\n" " limited, as you need to specifiy the questionnaire ID to select the " "sheet\n" " which should be updated." msgstr "" "Importar o exportar datos a/desde un archivo CSV. La primera línea\n" " es un encabezado que define questionnaire_id y global_id, así como una " "columna\n" " para cada casilla de verificación y campo de texto. Tenga en cuenta que " "actualmente la\n" " importación es muy limitada, dado que debe especificar el ID del " "cuestionario para seleccionar\n" " la hoja que debe actualizarse." #: ../sdaps/cmdline/csvdata.py:44 msgid "Export data to CSV file." msgstr "Exportar datos a un archivo CSV." #: ../sdaps/cmdline/csvdata.py:46 #, python-format msgid "Filename to store the data to (default: data_%%i.csv)" msgstr "" "Nombre del archivo para almacenar los datos (por defecto: data_%%i.csv)" #: ../sdaps/cmdline/csvdata.py:48 msgid "The delimiter used in the CSV file (default ',')" msgstr "El delimitador empleado en el archivo CSV (por defecto ',')" #: ../sdaps/cmdline/csvdata.py:52 ../sdaps/cmdline/report.py:31 #: ../sdaps/cmdline/reporttex.py:52 msgid "Filter to only export a partial dataset." msgstr "Filtro para exportar solamente un conjunto parcial de datos." #: ../sdaps/cmdline/csvdata.py:54 msgid "Export images of freeform fields." msgstr "Exportar imágenes de los campos de forma libre." #: ../sdaps/cmdline/csvdata.py:60 msgid "Export an image for each question that includes all boxes." msgstr "" "Exportar una imagen para cada pregunta que incluye a todos los recuadros." #: ../sdaps/cmdline/csvdata.py:66 msgid "Export the recognition quality for each checkbox." msgstr "" #: ../sdaps/cmdline/csvdata.py:74 msgid "Import data to from a CSV file." msgstr "Importar datos desde un archivo CSV." #: ../sdaps/cmdline/csvdata.py:76 msgid "The file to import." msgstr "El archivo a importar." #: ../sdaps/cmdline/gui.py:28 #, fuzzy msgid "Launch a GUI. You can view and alter the (recognized) answers with it." msgstr "" "Lanzar una interfaz gráfica. Puede ver y modificar las respuestas " "(reconocidas) con ella." #: ../sdaps/cmdline/gui.py:29 #, fuzzy msgid "" "This command launches a graphical user interface that can\n" " be used to correct answers. You need to run \"recognize\" before using " "it.\n" " " msgstr "" "Este comando inicia una interfaz gráfica que puede utilizarse \n" "para corregir la respuesta. Necesitará ejecutar \"recognize\" antes de " "emplearlo.\n" " " #: ../sdaps/cmdline/gui.py:34 msgid "Filter to only show a partial dataset." msgstr "Filtro para mostrar sólo un conjunto de datos parcial." #: ../sdaps/cmdline/ids.py:29 msgid "Export and import questionnaire IDs." msgstr "Exportación e importación de IDs de cuestionarios." #: ../sdaps/cmdline/ids.py:30 msgid "" "This command can be used to import and export questionnaire\n" " IDs. It only makes sense in projects where such an ID is printed on the\n" " questionnaire. Note that you can also add IDs by using the stamp " "command,\n" " which will give you the PDF at the same time." msgstr "" "Este comando puede utilizarse para importar y exportar IDs de cuestionarios " "IDs. Sólo tiene sentido en proyectos donde el ID se imprime en el " "cuestionario.\n" " Tenga en cuenta que también puede agregar IDs mediante el comando stamp,\n" " el cual le dará el PDF al mismo tiempo." #: ../sdaps/cmdline/ids.py:35 #, python-format msgid "Filename to store the data to (default: ids_%%i)" msgstr "Nombre del archivo para almacenar los datos (por defecto: ids_%%i)" #: ../sdaps/cmdline/ids.py:38 msgid "Add IDs to the internal list from the specified file." msgstr "Agregar IDs a la lista interna del archivo especificado." #: ../sdaps/cmdline/info.py:28 msgid "Display and modify metadata of project." msgstr "Visualizar y modificar los metadatos del proyecto." #: ../sdaps/cmdline/info.py:29 msgid "" "This command lets you modify the metadata of the SDAPS\n" " project. You can modify, add and remove arbitrary keys that will be " "printed\n" " on the report. The only key that always exist is \"title\".\n" " If no key is given then a list of defined keys is printed." msgstr "" "Este comando permite modificar los metadatos del proyecto SDAPS.\n" " Usted puede modificar, agregar y quitar claves arbitrarias que se " "imprimirán\n" " en el informe. La única llave que siempre existen es \"título\".\n" " Si no se proporciona ninguna llave entonces se imprime una lista de claves " "ya\n" " definidas." #: ../sdaps/cmdline/info.py:36 msgid "Delete the key and value pair." msgstr "Eliminar el par de llave y valor." #: ../sdaps/cmdline/info.py:40 msgid "The key to display or modify." msgstr "La llave para mostrar o modificar." #: ../sdaps/cmdline/info.py:44 msgid "Set the given key to this value." msgstr "Establecer la clave dada a este valor." #: ../sdaps/cmdline/info.py:69 msgid "Existing fields:\n" msgstr "Campos existentes:\n" #: ../sdaps/cmdline/recognize.py:28 msgid "Run the optical mark recognition." msgstr "Ejecutar el reconocimiento óptico de marcas." #: ../sdaps/cmdline/recognize.py:29 msgid "" "Iterates over all images and runs the optical mark\n" " recognition. It will reevaluate sheets even if \"recognize\" has " "already\n" " run or manual changes were made." msgstr "" "Itera sobre todas las imágenes y ejecuta el reconocimiento óptico↵\n" " de marcas. Se reevaluarían las hojas incluso si se ha ejecutado " "\"recognize\"↵\n" " o si se han realizado cambios manualmente." #: ../sdaps/cmdline/recognize.py:34 msgid "" "Only identify the page properties, but don't recognize the checkbox states." msgstr "" "Sólo identifica las propiedades de la página, pero no se reconocen las " "respuestas." #: ../sdaps/cmdline/recognize.py:39 msgid "" "Rerun the recognition for all pages. The default is to skip all pages that " "were recognized or verified already." msgstr "" "Ejecute nuevamente el reconocimiento para todas las páginas. Por defecto se " "omiten las ya reconocidas o verificadas." #: ../sdaps/cmdline/reorder.py:26 msgid "Reorder pages according to questionnaire ID." msgstr "Reordenar páginas de acuerdo con el ID de los cuestionarios." #: ../sdaps/cmdline/reorder.py:27 msgid "" "This command reorders all pages according to the already\n" " recognized questionnaire ID. To use it add all the files to the " "project,\n" " then run a partial recognition using \"recognize --identify\". After " "this\n" " you have to run this command to reorder the data for the real " "recognition.\n" " " msgstr "" "Este comando reordena todas las páginas por las IDs ya reconocidas de↵\n" " los cuestionarios. Para utilizarlo se deben añadir todos los archivos al " "proyecto y↵\n" " después realizar un reconocimiento parcial usando \"recognize --identify" "\". Luego↵\n" " hay que ejecutar este comando para reordenar los datos antes del " "reconocimiento.\n" " " #: ../sdaps/cmdline/report.py:26 msgid "Create a PDF report." msgstr "Crear un informe en PDF." #: ../sdaps/cmdline/report.py:27 msgid "" "This command creates a PDF report using reportlab that\n" " contains statistics and if selected the freeform fields." msgstr "" "Esta orden crea un informe en PDF utilizando reportlab que↵\n" " contiene estadísticas y los campos de forma libre, si se han " "seleccionado." #: ../sdaps/cmdline/report.py:33 msgid "Create a filtered report for every checkbox." msgstr "Crear un informe filtrado para cada casilla." #: ../sdaps/cmdline/report.py:36 msgid "Short format (without freeform text fields)." msgstr "Formato corto (sin campos de texto de forma libre)." #: ../sdaps/cmdline/report.py:41 msgid "Detailed output. (default)" msgstr "Salida detallada. (por defecto)" #: ../sdaps/cmdline/report.py:47 ../sdaps/cmdline/reporttex.py:30 msgid "" "Do not include original images in the report. This is useful if there are " "privacy concerns." msgstr "" "No incluir imágenes originales en el informe. Esto es útil si hubiera " "preocupación por la privacidad." #: ../sdaps/cmdline/report.py:52 ../sdaps/cmdline/reporttex.py:35 msgid "Do not use substitutions instead of images." msgstr "No utilizar sustituciones en vez de imágenes." #: ../sdaps/cmdline/report.py:58 ../sdaps/cmdline/reporttex.py:46 msgid "The paper size used for the output (default: locale dependent)" msgstr "" "El tamaño del papel utilizado para la salida (por defecto: depende de " "ajustes locales)" #: ../sdaps/cmdline/report.py:61 ../sdaps/cmdline/reporttex.py:49 #, python-format msgid "Filename to store the data to (default: report_%%i.pdf)" msgstr "" "Nombre del archivo para almacenar los datos (por defecto: report_%%i.pdf)" #: ../sdaps/cmdline/reporttex.py:26 msgid "Create a PDF report using LaTeX." msgstr "Crea un informe en PDF utilizando LaTeX." #: ../sdaps/cmdline/reporttex.py:27 msgid "" "This command creates a PDF report using LaTeX that\n" " contains statistics and freeform fields." msgstr "" "Este comando crea un informe PDF utilizando LaTex que↵\n" " contiene estadísticas y campos de forma libre." #: ../sdaps/cmdline/reporttex.py:41 msgid "Save the generated TeX files instead of the final PDF." msgstr "Guarda los archivos TeX generados en vez del PDF final." #: ../sdaps/cmdline/reset.py:26 msgid "Reset project into original state" msgstr "" #: ../sdaps/cmdline/reset.py:27 msgid "" "This command does a full reset of the project. All data\n" " will be discarded and only the empty project is left.\n" " " msgstr "" #: ../sdaps/cmdline/setup.py:27 msgid "Create a new survey using a LaTeX document." msgstr "Crear una nueva encuesta utilizando un documento LaTeX." #: ../sdaps/cmdline/setup.py:28 msgid "" "Create a new survey from a LaTeX document. You need to\n" " be using the SDAPS class. All the metadata and options for the project\n" " can be set inside the LaTeX document." msgstr "" "Crear una nueva encuesta desde un documento LaTeX. Es necesario estar↵\n" " utilizando la clase SDAPS. Todos los metadatos y opciones para el " "proyecto↵\n" " pueden ser definidos en el documento LaTeX." #: ../sdaps/cmdline/setup.py:33 msgid "The LaTeX Document" msgstr "El documento LaTeX" #: ../sdaps/cmdline/setup.py:35 msgid "" "Additional files that are required by the LaTeX document and need to be " "copied into the project directory." msgstr "" "Ficheros adicionares que son necesarios para el documento LaTeX y que " "necesitan ser copiados en el directorio del proyecto." #: ../sdaps/cmdline/setup.py:39 msgid "Additional questions that are not part of the questionnaire." msgstr "Otras preguntas que no forman parte del cuestionario." #: ../sdaps/cmdline/stamp.py:26 msgid "Add marks for automatic processing." msgstr "Añadir marcas para el procesamiento automático." #: ../sdaps/cmdline/stamp.py:27 msgid "" "This command creates the printable document. Depending on\n" " the projects setting you are required to specifiy a source for " "questionnaire\n" " IDs." msgstr "" "Este comando crea el documento para la impresión. Dependiendo de las↵\n" " configuraciones del proyecto se debe especificar un origen para los↵\n" " IDs del cuestionario." #: ../sdaps/cmdline/stamp.py:33 msgid "" "If using questionnaire IDs, create N questionnaires with randomized IDs." msgstr "" "Si se están utilizando IDs de cuestionario, crear N cuestionarios con IDs " "aleatorios." #: ../sdaps/cmdline/stamp.py:36 msgid "" "If using questionnaire IDs, create questionnaires from the IDs read from the " "specified file." msgstr "" "Si se están utilizando IDs de cuestionario, crear cuestionarios desde las " "IDs leídas en el fichero especificado." #: ../sdaps/cmdline/stamp.py:39 msgid "If using questionnaire IDs, create questionnaires for all stored IDs." msgstr "" "Si se están utilizando IDs de cuestionario, crear cuestionarios para todas " "las IDs almacenadas." #: ../sdaps/cmdline/stamp.py:42 #, python-format msgid "Filename to store the data to (default: stamp_%%i.pdf)" msgstr "" "Nombre del archivo para almacenar los datos (por defecto: stamp_%%i.pdf)" #: ../sdaps/convert/__init__.py:37 #, python-format msgid "Could not apply 3D-transformation to image '%s', page %i!" msgstr "" "No fue posible aplicar la transformación 3D a la imagen '%s', página %i!" #: ../sdaps/cover/__init__.py:40 #, fuzzy msgid "SDAPS questionnaire" msgstr "cuestionario de sdaps" #: ../sdaps/csvdata/buddies.py:77 #, fuzzy, python-format msgid "Not importing unknown questionnaire ID \"%s\"" msgstr "Exportación e importación de IDs de cuestionarios." #: ../sdaps/gui/__init__.py:59 msgid "" "The survey does not have any images! Please add images (and run recognize) " "before using the GUI." msgstr "" "¡La encuesta no tiene ninguna imagen! Por favor añadir imágenes (y ejecutar " "reconocimiento) antes de emplear la GUI." #: ../sdaps/gui/__init__.py:211 msgid "Page|Invalid" msgstr "Página|No válida" #: ../sdaps/gui/__init__.py:214 #, python-format msgid "Page %i" msgid_plural "Page %i" msgstr[0] "Página %i" msgstr[1] "Página %i" #: ../sdaps/gui/__init__.py:256 msgid "Copyright © 2007-2014 The SDAPS Authors" msgstr "Copyright © 2007-2014 los autores SDAPS" #: ../sdaps/gui/__init__.py:258 msgid "Scripts for data acquisition with paper based surveys" msgstr "Guiones para la adquisición de datos en encuestas impresas" #: ../sdaps/gui/__init__.py:259 msgid "http://sdaps.org" msgstr "http://sdaps.org" #: ../sdaps/gui/__init__.py:260 #, fuzzy msgid "translator-credits" msgstr "Traductor-créditos" #: ../sdaps/gui/__init__.py:305 #, python-format msgid " of %i" msgstr " de %i" #: ../sdaps/gui/__init__.py:306 #, python-format msgid "Recognition Quality: %.2f" msgstr "Calidad de reconocimiento: %.2f" #: ../sdaps/gui/__init__.py:322 msgid "" "You have reached the first page of the survey. Would you like to go to the " "last page?" msgstr "" "Ha llegado a la primera página de la encuesta. ¿Desea ir a la última página?" #: ../sdaps/gui/__init__.py:324 msgid "Go to last page" msgstr "Ir a la última página" #: ../sdaps/gui/__init__.py:346 msgid "" "You have reached the last page of the survey. Would you like to go to the " "first page?" msgstr "" "Ha llegado a la última página de la encuesta. ¿Desea ir a la primera página?" #: ../sdaps/gui/__init__.py:348 msgid "Go to first page" msgstr "Ir a la primera página" #: ../sdaps/gui/__init__.py:457 msgid "Close without saving" msgstr "Cerrar sin guardar" #: ../sdaps/gui/__init__.py:461 msgid "" "Save the project before closing?\n" "\n" "If you do not save you may loose data." msgstr "" "¿Guardar el proyecto antes de cerrar?\n" "\n" "Si no guarda puede perder datos." #: ../sdaps/gui/main_window.ui.h:1 msgid "Forward" msgstr "Adelante" #: ../sdaps/gui/main_window.ui.h:2 msgid "Previous" msgstr "Anterior" #: ../sdaps/gui/main_window.ui.h:3 msgid "Zoom In" msgstr "Acercar" #: ../sdaps/gui/main_window.ui.h:4 msgid "Zoom Out" msgstr "Alejar" #: ../sdaps/gui/main_window.ui.h:5 msgid "SDAPS" msgstr "SDAPS" #: ../sdaps/gui/main_window.ui.h:6 msgid "_File" msgstr "_Archivo" #: ../sdaps/gui/main_window.ui.h:7 msgid "_View" msgstr "_Ver" #: ../sdaps/gui/main_window.ui.h:8 msgid "_Help" msgstr "_Ayuda" #: ../sdaps/gui/main_window.ui.h:9 msgid "Page Rotated" msgstr "Página rotada" #: ../sdaps/gui/main_window.ui.h:10 msgid "Sort by Quality" msgstr "Ordenar por Calidad" #: ../sdaps/gui/main_window.ui.h:11 msgid "label" msgstr "etiqueta" #: ../sdaps/gui/widget_buddies.py:56 msgid "Global Properties" msgstr "Propiedades globales" #: ../sdaps/gui/widget_buddies.py:60 msgid "Sheet valid" msgstr "Hoja válida" #: ../sdaps/gui/widget_buddies.py:61 #, fuzzy msgid "Sheet Verified" msgstr "Verificado" #: ../sdaps/gui/widget_buddies.py:62 #, fuzzy msgid "Page Verified" msgstr "Verificado" #: ../sdaps/gui/widget_buddies.py:63 msgid "Empty" msgstr "Vacío" #: ../sdaps/gui/widget_buddies.py:75 ../sdaps/gui/widget_buddies.py:105 msgid "Questionnaire ID: " msgstr "ID del Cuestionario: " #: ../sdaps/image/__init__.py:47 msgid "" "It appears you have not build the C extension. Please run \"./setup.py build" "\" in the toplevel directory." msgstr "" "Parece que no se ha construído la extensión C. Ejecute \"./setup.py build\" " "en el directorio de nivel superior." #: ../sdaps/utils/latex.py:29 msgid "" "The latex character map is missing! Please build it using the supplied tool " "(create-latexmap.py)." msgstr "" #: ../sdaps/utils/latex.py:69 msgid "" "Generated string for LaTeX contains unicode characters. This may not work " "correctly and could mean the LaTeX character map needs to be updated." msgstr "" #: ../sdaps/utils/opencv.py:35 msgid "Cannot convert PDF files as poppler is not installed or usable!" msgstr "" "¡No se pueden convertir los archivos PDF porque poppler no está instalado o " "no se puede utilizar!" #: ../sdaps/utils/opencv.py:44 msgid "File does not exist" msgstr "" #. The old code used to first filter, and then run; but that is #. a bit ineffective in a way #: ../sdaps/model/survey.py:386 #, python-format msgid "%i sheet" msgid_plural "%i sheets" msgstr[0] "%i hoja" msgstr[1] "%i hojas" #: ../sdaps/model/survey.py:402 #, python-format msgid "Processed %i of %i sheets, took %f seconds" msgstr "" #: ../sdaps/model/survey.py:449 msgid "" "A questionnaire that is printed in duplex needs an even amount of pages!" msgstr "" "¡Un cuestionario que se imprime en dúplex necesita una cantidad par de " "páginas!" #: ../sdaps/model/survey.py:453 msgid "" "The 'classic' style only supports a maximum of six pages! Use the 'code128' " "style if you require more pages." msgstr "" "¡El estilo 'clásico' sólo admite un máximo de seis páginas! Utilice el " "estilo 'code128' si requiere de más páginas." #: ../sdaps/model/survey.py:466 msgid "IDs need to be integers in \"classic\" style!" msgstr "¡Los IDs deben ser enteros en el estilo clásico!" #: ../sdaps/model/survey.py:472 #, python-format msgid "Invalid character %s in questionnaire ID \"%s\" in \"code128\" style!" msgstr "" "¡Caracter inválido %s en el ID del cuestionario \"%s\" en el estilo " "\"code128\"!" #: ../sdaps/model/survey.py:476 msgid "" "SDAPS cannot draw a questionnaire ID with the \"custom\" style. Do this " "yourself somehow!" msgstr "" "SDAPS no puede dibujar un cuestionario ID en el estilo \"custom\" ¡Debe " "Hacerlo por sí mismo de alguna manera!" #. in simplex mode every page will have a matrix; it might be a None #. matrix though #: ../sdaps/recognize/buddies.py:71 #, python-format msgid "%s, %i: Matrix not recognized." msgstr "%s, %i: Matriz no reconocida." #: ../sdaps/recognize/buddies.py:80 #, python-format msgid "%s, %i: Rotation not found." msgstr "%s, %i: Rotación no encontrada." #. Copy the rotation over (if required) and print warning if the rotation is unknown #: ../sdaps/recognize/buddies.py:84 #, python-format msgid "Neither %s, %i or %s, %i has a known rotation!" msgstr "¡Ni %s, %i o %s, %i tienen una rotación conocida!" #: ../sdaps/recognize/buddies.py:96 #, python-format msgid "%s, %i: Matrix not recognized (again)." msgstr "%s, %i: Matriz no reconocida (otra vez)." #: ../sdaps/recognize/buddies.py:110 #, python-format msgid "%s, %i: Could not get page number." msgstr "%s, %i: No se pudo obtener el número de página." #. Whoa, that should not happen. #: ../sdaps/recognize/buddies.py:130 #, python-format msgid "Neither %s, %i or %s, %i has a known page number!" msgstr "¡Ni %s, %i o %s, %i tienen un número de página conocido!" #. We don't touch the ignore flag in this case #. Simply print a message as this should *never* happen #: ../sdaps/recognize/buddies.py:141 #, python-format msgid "" "Got a simplex document where two adjacent pages had a known page number. " "This should never happen as even simplex scans are converted to duplex by " "inserting dummy pages. Maybe you did a simplex scan but added it in duplex " "mode? The pages in question are %s, %i and %s, %i." msgstr "" "Se obtuvo un documento simple donde dos páginas adyacentes tenían un número " "de página conocido. Esto nunca debe suceder dado que incluso exploraciones " "simples se convierten en dúplex insertando páginas vacías. ¿Tal vez se " "realizó un escáneo simple pero se añadió en modo duplex? Las páginas en " "cuestión son %s, %i y %s, %i." #: ../sdaps/recognize/buddies.py:158 #, python-format msgid "Images %s, %i and %s, %i do not have consecutive page numbers!" msgstr "" "¡Las imágenes %s, %i y %s, %i no tienen números de página consecutivos!" #: ../sdaps/recognize/buddies.py:174 #, python-format msgid "No page number for page %s, %i exists." msgstr "No existe número de página para la página %s, %i." #: ../sdaps/recognize/buddies.py:179 #, python-format msgid "Page number for page %s, %i already used by another image." msgstr "" "El número de página para la página %s, %i ya es utilizado por otra imagen." #: ../sdaps/recognize/buddies.py:185 #, python-format msgid "Page number %i for page %s, %i is out of range." msgstr "El número de página %i para la página %s, %i está fuera de rango." #: ../sdaps/recognize/buddies.py:202 #, python-format msgid "%s, %i: Could not read survey ID, but should be able to." msgstr "" "%s, %i: No se pudo leer el ID del reconocimiento, pero debiera ser capaz de " "hacerse." #: ../sdaps/recognize/buddies.py:206 #, python-format msgid "Could not read survey ID of either %s, %i or %s, %i!" msgstr "No se pudo leer el ID de la encuesta de %s, %i o %s, %i!" #. Broken survey ID ... #: ../sdaps/recognize/buddies.py:213 #, python-format msgid "Got a wrong survey ID (%s, %i)! It is %s, but should be %i." msgstr "" "Se obtuvo una identificación equivocada de la encuesta (%s, %i)! Es %s, pero " "debe ser %i." #: ../sdaps/recognize/buddies.py:235 #, python-format msgid "%s, %i: Could not read questionnaire ID, but should be able to." msgstr "" "%s, %i: No se pudo leer el ID del cuestionario, pero usted debe ser capaz de " "hacerlo." #: ../sdaps/recognize/buddies.py:241 #, python-format msgid "Could not read questionnaire ID of either %s, %i or %s, %i!" msgstr "No se pudo leer el ID del cuestionario de %s, %i o %s, %i!" #: ../sdaps/recognize/buddies.py:271 msgid "" "Got different IDs on different pages for at least one sheet! Do *NOT* try to " "use filters with this survey! You have to run a \"reorder\" step for this to " "work properly!" msgstr "" "¡Se obtuvieron diferentes IDs en las diferentes páginas para por lo menos " "una hoja! *NO* intentar utilizar filtros con esta encuesta! ¡Tiene que " "ejecutar el paso de \"reordenar\" para que ello funcione correctamente!" #: ../sdaps/recognize/buddies.py:326 msgid "No style buddy loaded. This needs to be done for the \"custom\" style!" msgstr "" "No se ha cargado definición de estilo. ¡Esto se debe hacer para el estilo " "\"custom\"!" #: ../sdaps/report/answers.py:188 #, python-format msgid "Answers: %i" msgstr "Respuestas: %i" #: ../sdaps/report/answers.py:190 #, python-format msgid "Mean: %.2f" msgstr "Media: %.2f" #: ../sdaps/report/answers.py:192 #, python-format msgid "Standard Deviation: %.2f" msgstr "Desviación Típica: %.2f" #: ../sdaps/report/__init__.py:75 ../sdaps/reporttex/__init__.py:140 msgid "Turned in Questionnaires" msgstr "Cantidad de cuestionarios" #: ../sdaps/report/__init__.py:92 ../sdaps/reporttex/__init__.py:139 msgid "sdaps report" msgstr "informe sdaps" #: ../sdaps/reset/__init__.py:29 msgid "Removing stored data..." msgstr "" #: ../sdaps/setup/buddies.py:62 #, python-format msgid "Head %(l0)i got no title." msgstr "La cabecera %(l0)i no tiene título." #: ../sdaps/setup/buddies.py:74 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no question." msgstr "%(class)s %(l0)i.%(l1)i no contiene preguntas." #: ../sdaps/setup/buddies.py:114 #, python-format msgid "Error in question \"%s\"" msgstr "Error en la pregunta \"%s\"" #: ../sdaps/setup/buddies.py:118 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no boxes." msgstr "%(class)s %(l0)i.%(l1)i no tiene casillas." #: ../sdaps/setup/buddies.py:167 #, fuzzy, python-format msgid "%(class)s %(l0)i.%(l1)i lower box out of range." msgstr "%(class)s %(l0)i.%(l1)i no contiene preguntas." #: ../sdaps/setup/buddies.py:172 #, fuzzy, python-format msgid "%(class)s %(l0)i.%(l1)i upper box out of range." msgstr "%(class)s %(l0)i.%(l1)i no tiene casillas." #: ../sdaps/setup/buddies.py:177 #, fuzzy, python-format msgid "%(class)s %(l0)i.%(l1)i lower box not before upper box." msgstr "%(class)s %(l0)i.%(l1)i no tiene exactamente una casilla." #: ../sdaps/setup/buddies.py:213 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly two answers." msgstr "%(class)s %(l0)i.%(l1)i no tiene exactamente dos respuestas." #: ../sdaps/setup/buddies.py:234 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly one box." msgstr "%(class)s %(l0)i.%(l1)i no tiene exactamente una casilla." #: ../sdaps/stamp/__init__.py:38 msgid "" "You may not specify the number of sheets for this survey. All questionnaires " "will be identical as the survey has been configured to not use questionnaire " "IDs for each sheet." msgstr "" "No debe especificar el número de hojas para esta encuesta. Todos los " "cuestionarios serán idénticos, ya que se ha especificado que no se usen IDs " "de cuestionario en cada hoja." #: ../sdaps/stamp/__init__.py:76 msgid "" "This survey has been configured to use questionnaire IDs. Each questionnaire " "will be unique. You need to use on of the options to add new IDs or use the " "existing ones." msgstr "" "Se ha configurado que esta encuesta utilice IDs de cuestionario. Cada " "cuestionario será único. Por tanto, debe indicar si se utilizarán nuevos IDs " "o los ya almacenados." #: ../sdaps/stamp/latex.py:18 msgid "" "There should be no need to stamp a SDAPS Project that uses LaTeX and does " "not have different questionnaire IDs printed on each sheet.\n" "I am going to do so anyways." msgstr "" "No debería ser necesario estampar un proyecto SDAPS que utiliza LaTeX y no " "tiene diferentes IDs de cuestionario impreso en cada hoja.↵\n" "Lo voy a hacer igualmente." #: ../sdaps/stamp/latex.py:26 #, python-format msgid "Running %s now twice to generate the stamped questionnaire." msgstr "Ejecutando %s dos veces para generar el cuestionario estampado." #: ../sdaps/stamp/latex.py:30 ../sdaps/setuptex/__init__.py:107 #: ../sdaps/setuptex/__init__.py:148 ../sdaps/reporttex/__init__.py:162 #, python-format msgid "Error running \"%s\" to compile the LaTeX file." msgstr "Error ejecutando \"%s\" para compilar el archivo LaTeX." #: ../sdaps/stamp/latex.py:36 #, python-format msgid "" "An error occured during creation of the report. Temporary files left in '%s'." msgstr "" "Se produjo un error durante la creación del informe. Los archivos temporales " "se hallan en '%s'." #: ../sdaps/setuptex/__init__.py:46 msgid "The survey directory already exists." msgstr "El directorio de la encuesta ya existe." #: ../sdaps/setuptex/__init__.py:51 #, python-format msgid "Unknown file type (%s). questionnaire_tex should be of type text/x-tex." msgstr "" "Tipo de archivo desconocido (%s). questionnaire_tex debería ser del tipo " "text/x-tex." #: ../sdaps/setuptex/__init__.py:52 msgid "Will keep going, but expect failure!" msgstr "¡Se continuará, pero se esperan errores!" #: ../sdaps/setuptex/__init__.py:57 #, python-format msgid "Unknown file type (%s). additionalqobjects should be text/plain." msgstr "" "Tipo de archivo desconocido (%s). additionalqobjects debe ser del tipo text/" "plain." #: ../sdaps/setuptex/__init__.py:103 ../sdaps/setuptex/__init__.py:143 #, python-format msgid "Running %s now twice to generate the questionnaire." msgstr "Ejecutando %s dos veces para generar el cuestionario." #: ../sdaps/setuptex/__init__.py:122 msgid "Caught an Exception while parsing the SDAPS file. The current state is:" msgstr "" "Se produjo una excepción al analizar el archivo SDAPS. El estado actual es:" #: ../sdaps/setuptex/__init__.py:136 msgid "" "Some combination of options and project properties do not work. Aborted " "Setup." msgstr "" "Alguna combinación de opciones y propiedades del proyecto no funciona. " "Instalación interrumpida." #: ../sdaps/setuptex/__init__.py:162 msgid "" "An error occured in the setup routine. The survey directory still exists. " "You can for example check the questionnaire.log file for LaTeX compile " "errors." msgstr "" "Se produjo un error durante la instalación. El directorio de la encuesta " "todavía existe. Puede ver por ejemplo el archivo questionnaire.log para " "verificar errores de compilación de LaTeX." #: ../sdaps/reporttex/__init__.py:107 msgid "author|Unknown" msgstr "autor|Desconocido" #: ../sdaps/reporttex/__init__.py:138 msgid "tex language|english" msgstr "lenguaje tex|inglés" #: ../sdaps/reporttex/__init__.py:155 #, python-format msgid "The TeX project with the report data is located at '%s'." msgstr "El proyecto TeX con los datos del informe se halla en '%s'." #: ../sdaps/reporttex/__init__.py:158 #, python-format msgid "Running %s now twice to generate the report." msgstr "Ejecutando %s dos veces para generar el informe." #: ../sdaps/reporttex/__init__.py:168 #, python-format msgid "An occured during creation of the report. Temporary files left in '%s'." msgstr "" "Se produjo un error durante la creación del informe. Los archivos temporales " "se hallan en '%s'." #~ msgid "%f seconds per sheet" #~ msgstr "%f segundos por hoja" #~ msgid "Running upgrade routines for file format version %i" #~ msgstr "" #~ "Ejecutando rutinas de actualización para la versión de formato de archivo " #~ "%i" #~ msgid "Create a new survey using an ODT document." #~ msgstr "Crear un cuestionario nuevo utilizando un documento ODT." #~ msgid "" #~ "Create a new surevey from an ODT document. The PDF export\n" #~ " of the file needs to be specified at the same time. SDAPS will " #~ "import\n" #~ " metadata (properties) and the title from the ODT document." #~ msgstr "" #~ "Crea un nuevo cuestionario a partir de un documento ODT. El archivo en " #~ "PDF↵\n" #~ " exportado debe ser especificado al mismo tiempo. SDAPS importará↵\n" #~ " los metadatos (propiedades) y el título desde el documento ODT." #~ msgid "The ODT Document" #~ msgstr "El documento ODT" #~ msgid "PDF export of the ODT document" #~ msgstr "Archivo PDF exportado a partir del documento ODT" #~ msgid "Enable printing of the survey ID (default)." #~ msgstr "Activar la impresión del ID del cuestionario (por defecto)." #~ msgid "Disable printing of the survey ID." #~ msgstr "Desactivar la impresión del ID del cuestionario." #~ msgid "Enable printing of the questionnaire ID." #~ msgstr "Activar la impresión del ID del cuestionario." #~ msgid "Disable printing of the questionnaire ID (default)." #~ msgstr "Desactivar la impresión del ID del cuestionario (por defecto)." #~ msgid "" #~ "Set an additional global ID for tracking. This can can only be used in " #~ "the \"code128\" style." #~ msgstr "" #~ "Definir un ID globar para la monitorización. Sólo se puede emplear en el " #~ "estilo \"code128\"." #~ msgid "" #~ "The stamping style to use. Should be either \"classic\" or \"code128\". " #~ "Use \"code128\" for more features." #~ msgstr "" #~ "El estilo utilizado para estampar. Debe ser \"classic\" o \"code128\". " #~ "Use \"code128\" para tener más recursos disponibles." #~ msgid "The mode to use when detecting checkboxes." #~ msgstr "El modo a utilizar para detectar casillas." #~ msgid "" #~ "Use duplex mode (ie. only print the IDs on the back side). Requires a " #~ "mulitple of two pages." #~ msgstr "" #~ "Utilizar modo duplex (esto es, imprimir sólo los IDs en el reverso de las " #~ "hojas). Requiere un múltiplo de dos páginas." #~ msgid "" #~ "Use simplex mode. IDs are printed on each page. You need a simplex scan " #~ "currently!" #~ msgstr "" #~ "Utilizar modo simplex. Los IDs se imprimen en cada página. ¡El escaneo " #~ "debe realizarse en modo simplex!" #~ msgid "" #~ "Unknown file type (%s). questionnaire_odt should be application/vnd.oasis." #~ "opendocument.text." #~ msgstr "" #~ "Tipo de archivo desconocido (%s). El questionnaire_odt debe ser del tipo " #~ "application/vnd.oasis.opendocument.text." #~ msgid "Unknown file type (%s). questionnaire_pdf should be application/pdf." #~ msgstr "" #~ "Tipo de archivo desconocido (%s). questionnaire_pdf debe ser del tipo " #~ "application/pdf." #~ msgid "" #~ "Caught an Exception while parsing the ODT file. The current state is:" #~ msgstr "" #~ "Se produjo una excepción al analizar el archivo ODT. El estado actual es:" #~ msgid "" #~ "If the dependencies for the \"annotate\" command are installed, then an " #~ "annotated version will be created next to the original PDF file." #~ msgstr "" #~ "Si las dependencias para el comando \"annotate\" están instaladas, se " #~ "creará una versión con anotaciones junto al archivo PDF original." #~ msgid "" #~ "Warning: Ignoring a box (page: %i, x: %.1f, y: %.1f, width: %.1f, height: " #~ "%.1f)." #~ msgstr "" #~ "Atención: Ignorando una caja (página: %i, x: %.1f, y: %.1f, anchura: " #~ "%.1f, altura: %.1f)." #~ msgid "Survey-ID: %i" #~ msgstr "ID de Encuesta: %i" #~ msgid "Questionnaire-ID: %i" #~ msgstr "ID de Cuestionario: %i" #, fuzzy #~ msgid "You need to have either PDFtk or pyPdf installed. PDFtk is faster." #~ msgstr "Debe tener instalado pdftk o pyPdf. pdftk es el método más rápido." #~ msgid "Creating stamp PDF for %i sheet" #~ msgid_plural "Creating stamp PDF for %i sheets" #~ msgstr[0] "Estampando PDF para la hoja %i" #~ msgstr[1] "Estampando PDF para las hojas %i" #~ msgid "%i sheet; %f seconds per sheet" #~ msgid_plural "%i sheet; %f seconds per sheet" #~ msgstr[0] "%i hoja; %f segundos por hoja" #~ msgstr[1] "%i hojas; %f segundos por hoja" #, fuzzy #~ msgid "Marking using PDFtk" #~ msgstr "Estampando utilizando pdftk" #, fuzzy #~ msgid "PDFtk: Overlaying the original PDF with the markings." #~ msgstr "pdftk: Creando una nueva capa en el PDF original con las marcas." #, fuzzy #~ msgid "PDFtk: Splitting out page %d of each stack." #~ msgid_plural "PDFtk: Splitting out page %d of each stack." #~ msgstr[0] "pdftk: Extrayendo la página %d de cada hoja." #~ msgstr[1] "pdftk: Extrayendo las páginas %d de cada hoja." #, fuzzy #~ msgid "PDFtk: Splitting the questionnaire for marking." #~ msgstr "pdftk: Dividiendo el cuestionario para la marca de agua." #, fuzzy #~ msgid "PDFtk: Marking page %d of all stacks." #~ msgid_plural "PDFtk: Marking page %d of all stacks." #~ msgstr[0] "pdftk: Creando marca de agua en la página %d de todas las hojas." #~ msgstr[1] "" #~ "pdftk: Creando marca de agua en las páginas %d de todas las hojas." #~ msgid "pdftk: Assembling everything into the final PDF." #~ msgstr "pdftk: Uniendo todo en el PDF final." #, fuzzy #~ msgid "Marking using pyPdf. For faster marking, install PDFtk." #~ msgstr "" #~ "Estampando usando pyPdf. Para estampación más rápida, instale pdftk." sdaps-1.9.8/po/fi.po0000644000175000000660000006362413410742232014764 0ustar benjaminlock00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: SDAPS\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:10+0100\n" "PO-Revision-Date: 2014-08-17 13:09+0200\n" "Last-Translator: Joonas Joensuu \n" "Language-Team: Finnish \n" "Language: fi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 1.10-dev\n" #: ../sdaps/script.py:41 msgid "SDAPS -- Paper based survey tool." msgstr "SDAPS -- Paperipohjainen kyselytyokalu." #: ../sdaps/script.py:45 msgid "command list|Commands:" msgstr "komentolistaus|Komennot:" #: ../sdaps/script.py:50 msgid "project directory|The SDAPS project." msgstr "projektin hakemisto|SDAPS-projekti." #: ../sdaps/add/__init__.py:55 #, python-format msgid "" "Invalid input file %s. You need to specify a (multipage) monochrome TIFF as " "input." msgstr "" "Virheellinen syötetiedosto %s. Syötetiedosto pitää olla muodossa " "(monisivuinen) yksivärinen TIFF." #: ../sdaps/add/__init__.py:67 #, python-format msgid "" "Not adding %s because it has a wrong page count (needs to be a mulitple of " "%i)." msgstr "" "Ei lisätä %s, koska sen sivumäärä on väärä (tarvitsee olla kerroin luvusta " "%i)." #: ../sdaps/boxgallery/__init__.py:108 #, fuzzy, python-format msgid "Rendering boxgallery for metric \"%s\"." msgstr "Renderöidään laatikkogalleria metriseksi \"%s\"." #: ../sdaps/log.py:37 msgid "Warning: " msgstr "Varoitus: " #: ../sdaps/log.py:41 msgid "Error: " msgstr "Virhe: " #: ../sdaps/cmdline/add.py:31 msgid "Add scanned questionnaires to the survey." msgstr "Lisää skannatut kyselylomakkeet kyselyyn." #: ../sdaps/cmdline/add.py:32 #, fuzzy msgid "" "This command is used to add scanned images to the survey.\n" " The image data needs to be a (multipage) 300dpi monochrome TIFF file. " "You\n" " may choose not to copy the data into the project directory. In that " "case\n" " the data will be referenced using a relative path." msgstr "" "Tällä komennolla voit lisätä skannattuja kuvia kyselyyn.\n" " Kuvatiedodoston tulee olla (monisivuinen) 300dpi mustavalko-TIFF-" "tiedosto.\n" " Voit olla kopioimatta tiedot projektin hakemistoon.\n" " Tässä tapauksessa tietoja käsitellään käyttämällä suhteellista polkua." #: ../sdaps/cmdline/add.py:38 msgid "Convert given files and add the result." msgstr "" #: ../sdaps/cmdline/add.py:43 msgid "" "Do a 3D-transformation after finding the corner marks. If the\n" " corner marks are not found then the image will be added as-is." msgstr "" #: ../sdaps/cmdline/add.py:49 msgid "" "Force adding the images even if the page count is wrong (only use if you " "know what you are doing)." msgstr "" "Pakota käyttämään kuvia, vaikka sivumäärä olisikin väärin (käytä vain, jos " "tiedä mitä olet tekemässä)." #: ../sdaps/cmdline/add.py:53 msgid "Copy the files into the directory (default)." msgstr "Kopioi tiedostot hakemistoon (oletus)." #: ../sdaps/cmdline/add.py:58 msgid "Do not copy the files into the directory." msgstr "Älä kopioi tiedostoja hakemistoon." #: ../sdaps/cmdline/add.py:62 msgid "" "Images contain a duplex scan of a simplex questionnaire (default: simplex " "scan)." msgstr "" "Kuvat sisältävät kaksipuolisen skannauksen yksipuolisesta kyselykaavakkeesta " "(oletus: yksipuolinen skannaus)." #: ../sdaps/cmdline/add.py:68 ../sdaps/cmdline/convert.py:48 msgid "A number of TIFF image files." msgstr "TIFF-kuvatiedostojen lukumäärä." #: ../sdaps/cmdline/add.py:94 msgid "The --no-copy option is not compatible with --convert!" msgstr "" #: ../sdaps/cmdline/add.py:103 msgid "Converting input files into a single temporary file." msgstr "" #: ../sdaps/cmdline/add.py:115 msgid "" "The page count of the created temporary file does not work with this survey." msgstr "" #: ../sdaps/cmdline/add.py:120 msgid "Running the conversion failed." msgstr "" #: ../sdaps/cmdline/add.py:126 #, python-format msgid "Processing %s" msgstr "Käsittelee %s" #: ../sdaps/cmdline/add.py:130 ../sdaps/reset/__init__.py:33 msgid "Done" msgstr "Valmis" #: ../sdaps/cmdline/annotate.py:28 #, fuzzy msgid "Annotate the questionnaire and show the recognized positions." msgstr "Lisää huomautuksia kyselykaavakkeeseen ja näytä tunnistetut sijainnit." #: ../sdaps/cmdline/annotate.py:29 #, fuzzy msgid "" "This command is mainly a debug utility. It creates an\n" " annotated version of the questionnaire, with the information that SDAPS\n" " knows about it overlayed on top." msgstr "" "Tämä komento on pääasiassa virheenkorjauksen apuohjelma. Se luo \n" " huomautuksilla varustetun version kyselylomakkeesta ja \n" " lisää SDAPS:in tietämän informaation sen päälle." #: ../sdaps/cmdline/boxgallery.py:31 msgid "Create PDFs with boxes sorted by the detection heuristics." msgstr "" "Luo PDF-tiedostot, joissa laatikot on lajiteltu tunnistusheuristiikan " "mukaisesti." #: ../sdaps/cmdline/boxgallery.py:32 msgid "" "SDAPS uses multiple heuristics to detect determine the\n" " state of checkboxes. There is a list for each heuristic giving the " "expected\n" " state and the quality of the value (see defs.py). Using this command a " "PDF\n" " will be created for each of the heuristics so that one can adjust the\n" " values." msgstr "" #: ../sdaps/cmdline/boxgallery.py:40 msgid "" "Reruns part of the recognition process and retrieves debug images from this " "step." msgstr "" #: ../sdaps/cmdline/convert.py:30 msgid "Convert a set of images to the correct image format." msgstr "" #: ../sdaps/cmdline/convert.py:31 msgid "" "This command can be used if you scanned files in something\n" " other than the expected monochrome TIFF mode. All given files will\n" " be loaded, converted to monochrome and stored in a multipage 1bpp\n" " TIFF file. Optionally, you can select \"3D transformation\"\\ ,which " "may facilitate\n" " working with photos of questionnaires instead of scans." msgstr "" #: ../sdaps/cmdline/convert.py:38 msgid "" "Do a 3D-transformation after finding the corner marks.\n" " If they are not found, the image will be processed as-is." msgstr "" #: ../sdaps/cmdline/convert.py:44 msgid "The location of the output file." msgstr "" #: ../sdaps/cmdline/convert.py:57 msgid "No output filename specified!" msgstr "" #: ../sdaps/cmdline/cover.py:27 msgid "Create a cover for the questionnaires." msgstr "" #: ../sdaps/cmdline/cover.py:28 msgid "" "This command creates a cover page for questionnaires. All\n" " the metadata of the survey will be printed on the page." msgstr "" #: ../sdaps/cmdline/cover.py:31 #, python-format msgid "Filename to store the data to (default: cover_%%i.pdf)" msgstr "" #: ../sdaps/cmdline/csvdata.py:34 msgid "Import or export data to/from CSV files." msgstr "" #: ../sdaps/cmdline/csvdata.py:35 msgid "" "Import or export data to/from a CSV file. The first line\n" " is a header which defines questionnaire_id and global_id, and a column\n" " for each checkbox and textfield. Note that the import is currently very\n" " limited, as you need to specifiy the questionnaire ID to select the " "sheet\n" " which should be updated." msgstr "" #: ../sdaps/cmdline/csvdata.py:44 msgid "Export data to CSV file." msgstr "" #: ../sdaps/cmdline/csvdata.py:46 #, python-format msgid "Filename to store the data to (default: data_%%i.csv)" msgstr "" #: ../sdaps/cmdline/csvdata.py:48 msgid "The delimiter used in the CSV file (default ',')" msgstr "" #: ../sdaps/cmdline/csvdata.py:52 ../sdaps/cmdline/report.py:31 #: ../sdaps/cmdline/reporttex.py:52 msgid "Filter to only export a partial dataset." msgstr "" #: ../sdaps/cmdline/csvdata.py:54 msgid "Export images of freeform fields." msgstr "" #: ../sdaps/cmdline/csvdata.py:60 msgid "Export an image for each question that includes all boxes." msgstr "" #: ../sdaps/cmdline/csvdata.py:66 msgid "Export the recognition quality for each checkbox." msgstr "" #: ../sdaps/cmdline/csvdata.py:74 msgid "Import data to from a CSV file." msgstr "" #: ../sdaps/cmdline/csvdata.py:76 msgid "The file to import." msgstr "" #: ../sdaps/cmdline/gui.py:28 msgid "Launch a GUI. You can view and alter the (recognized) answers with it." msgstr "" #: ../sdaps/cmdline/gui.py:29 msgid "" "This command launches a graphical user interface that can\n" " be used to correct answers. You need to run \"recognize\" before using " "it.\n" " " msgstr "" #: ../sdaps/cmdline/gui.py:34 msgid "Filter to only show a partial dataset." msgstr "" #: ../sdaps/cmdline/ids.py:29 msgid "Export and import questionnaire IDs." msgstr "" #: ../sdaps/cmdline/ids.py:30 msgid "" "This command can be used to import and export questionnaire\n" " IDs. It only makes sense in projects where such an ID is printed on the\n" " questionnaire. Note that you can also add IDs by using the stamp " "command,\n" " which will give you the PDF at the same time." msgstr "" #: ../sdaps/cmdline/ids.py:35 #, python-format msgid "Filename to store the data to (default: ids_%%i)" msgstr "" #: ../sdaps/cmdline/ids.py:38 msgid "Add IDs to the internal list from the specified file." msgstr "" #: ../sdaps/cmdline/info.py:28 msgid "Display and modify metadata of project." msgstr "" #: ../sdaps/cmdline/info.py:29 msgid "" "This command lets you modify the metadata of the SDAPS\n" " project. You can modify, add and remove arbitrary keys that will be " "printed\n" " on the report. The only key that always exist is \"title\".\n" " If no key is given then a list of defined keys is printed." msgstr "" #: ../sdaps/cmdline/info.py:36 msgid "Delete the key and value pair." msgstr "" #: ../sdaps/cmdline/info.py:40 msgid "The key to display or modify." msgstr "" #: ../sdaps/cmdline/info.py:44 msgid "Set the given key to this value." msgstr "" #: ../sdaps/cmdline/info.py:69 msgid "Existing fields:\n" msgstr "" #: ../sdaps/cmdline/recognize.py:28 msgid "Run the optical mark recognition." msgstr "" #: ../sdaps/cmdline/recognize.py:29 msgid "" "Iterates over all images and runs the optical mark\n" " recognition. It will reevaluate sheets even if \"recognize\" has " "already\n" " run or manual changes were made." msgstr "" #: ../sdaps/cmdline/recognize.py:34 msgid "" "Only identify the page properties, but don't recognize the checkbox states." msgstr "" #: ../sdaps/cmdline/recognize.py:39 msgid "" "Rerun the recognition for all pages. The default is to skip all pages that " "were recognized or verified already." msgstr "" #: ../sdaps/cmdline/reorder.py:26 msgid "Reorder pages according to questionnaire ID." msgstr "" #: ../sdaps/cmdline/reorder.py:27 msgid "" "This command reorders all pages according to the already\n" " recognized questionnaire ID. To use it add all the files to the " "project,\n" " then run a partial recognition using \"recognize --identify\". After " "this\n" " you have to run this command to reorder the data for the real " "recognition.\n" " " msgstr "" #: ../sdaps/cmdline/report.py:26 msgid "Create a PDF report." msgstr "" #: ../sdaps/cmdline/report.py:27 msgid "" "This command creates a PDF report using reportlab that\n" " contains statistics and if selected the freeform fields." msgstr "" #: ../sdaps/cmdline/report.py:33 msgid "Create a filtered report for every checkbox." msgstr "" #: ../sdaps/cmdline/report.py:36 msgid "Short format (without freeform text fields)." msgstr "" #: ../sdaps/cmdline/report.py:41 msgid "Detailed output. (default)" msgstr "" #: ../sdaps/cmdline/report.py:47 ../sdaps/cmdline/reporttex.py:30 msgid "" "Do not include original images in the report. This is useful if there are " "privacy concerns." msgstr "" #: ../sdaps/cmdline/report.py:52 ../sdaps/cmdline/reporttex.py:35 msgid "Do not use substitutions instead of images." msgstr "" #: ../sdaps/cmdline/report.py:58 ../sdaps/cmdline/reporttex.py:46 msgid "The paper size used for the output (default: locale dependent)" msgstr "" #: ../sdaps/cmdline/report.py:61 ../sdaps/cmdline/reporttex.py:49 #, python-format msgid "Filename to store the data to (default: report_%%i.pdf)" msgstr "" #: ../sdaps/cmdline/reporttex.py:26 msgid "Create a PDF report using LaTeX." msgstr "" #: ../sdaps/cmdline/reporttex.py:27 msgid "" "This command creates a PDF report using LaTeX that\n" " contains statistics and freeform fields." msgstr "" #: ../sdaps/cmdline/reporttex.py:41 msgid "Save the generated TeX files instead of the final PDF." msgstr "" #: ../sdaps/cmdline/reset.py:26 msgid "Reset project into original state" msgstr "" #: ../sdaps/cmdline/reset.py:27 msgid "" "This command does a full reset of the project. All data\n" " will be discarded and only the empty project is left.\n" " " msgstr "" #: ../sdaps/cmdline/setup.py:27 msgid "Create a new survey using a LaTeX document." msgstr "" #: ../sdaps/cmdline/setup.py:28 msgid "" "Create a new survey from a LaTeX document. You need to\n" " be using the SDAPS class. All the metadata and options for the project\n" " can be set inside the LaTeX document." msgstr "" #: ../sdaps/cmdline/setup.py:33 msgid "The LaTeX Document" msgstr "" #: ../sdaps/cmdline/setup.py:35 msgid "" "Additional files that are required by the LaTeX document and need to be " "copied into the project directory." msgstr "" #: ../sdaps/cmdline/setup.py:39 msgid "Additional questions that are not part of the questionnaire." msgstr "" #: ../sdaps/cmdline/stamp.py:26 msgid "Add marks for automatic processing." msgstr "" #: ../sdaps/cmdline/stamp.py:27 msgid "" "This command creates the printable document. Depending on\n" " the projects setting you are required to specifiy a source for " "questionnaire\n" " IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:33 msgid "" "If using questionnaire IDs, create N questionnaires with randomized IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:36 msgid "" "If using questionnaire IDs, create questionnaires from the IDs read from the " "specified file." msgstr "" #: ../sdaps/cmdline/stamp.py:39 msgid "If using questionnaire IDs, create questionnaires for all stored IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:42 #, python-format msgid "Filename to store the data to (default: stamp_%%i.pdf)" msgstr "" #: ../sdaps/convert/__init__.py:37 #, python-format msgid "Could not apply 3D-transformation to image '%s', page %i!" msgstr "" #: ../sdaps/cover/__init__.py:40 msgid "SDAPS questionnaire" msgstr "" #: ../sdaps/csvdata/buddies.py:77 #, python-format msgid "Not importing unknown questionnaire ID \"%s\"" msgstr "" #: ../sdaps/gui/__init__.py:59 msgid "" "The survey does not have any images! Please add images (and run recognize) " "before using the GUI." msgstr "" #: ../sdaps/gui/__init__.py:211 msgid "Page|Invalid" msgstr "" #: ../sdaps/gui/__init__.py:214 #, python-format msgid "Page %i" msgid_plural "Page %i" msgstr[0] "" msgstr[1] "" #: ../sdaps/gui/__init__.py:256 msgid "Copyright © 2007-2014 The SDAPS Authors" msgstr "" #: ../sdaps/gui/__init__.py:258 msgid "Scripts for data acquisition with paper based surveys" msgstr "" #: ../sdaps/gui/__init__.py:259 msgid "http://sdaps.org" msgstr "" #: ../sdaps/gui/__init__.py:260 msgid "translator-credits" msgstr "" #: ../sdaps/gui/__init__.py:305 #, python-format msgid " of %i" msgstr "" #: ../sdaps/gui/__init__.py:306 #, python-format msgid "Recognition Quality: %.2f" msgstr "" #: ../sdaps/gui/__init__.py:322 msgid "" "You have reached the first page of the survey. Would you like to go to the " "last page?" msgstr "" #: ../sdaps/gui/__init__.py:324 msgid "Go to last page" msgstr "" #: ../sdaps/gui/__init__.py:346 msgid "" "You have reached the last page of the survey. Would you like to go to the " "first page?" msgstr "" #: ../sdaps/gui/__init__.py:348 msgid "Go to first page" msgstr "" #: ../sdaps/gui/__init__.py:457 msgid "Close without saving" msgstr "" #: ../sdaps/gui/__init__.py:461 msgid "" "Save the project before closing?\n" "\n" "If you do not save you may loose data." msgstr "" #: ../sdaps/gui/main_window.ui.h:1 msgid "Forward" msgstr "" #: ../sdaps/gui/main_window.ui.h:2 msgid "Previous" msgstr "" #: ../sdaps/gui/main_window.ui.h:3 msgid "Zoom In" msgstr "" #: ../sdaps/gui/main_window.ui.h:4 msgid "Zoom Out" msgstr "" #: ../sdaps/gui/main_window.ui.h:5 msgid "SDAPS" msgstr "" #: ../sdaps/gui/main_window.ui.h:6 msgid "_File" msgstr "" #: ../sdaps/gui/main_window.ui.h:7 msgid "_View" msgstr "" #: ../sdaps/gui/main_window.ui.h:8 msgid "_Help" msgstr "" #: ../sdaps/gui/main_window.ui.h:9 msgid "Page Rotated" msgstr "" #: ../sdaps/gui/main_window.ui.h:10 msgid "Sort by Quality" msgstr "" #: ../sdaps/gui/main_window.ui.h:11 msgid "label" msgstr "" #: ../sdaps/gui/widget_buddies.py:56 msgid "Global Properties" msgstr "" #: ../sdaps/gui/widget_buddies.py:60 msgid "Sheet valid" msgstr "" #: ../sdaps/gui/widget_buddies.py:61 msgid "Sheet Verified" msgstr "" #: ../sdaps/gui/widget_buddies.py:62 msgid "Page Verified" msgstr "" #: ../sdaps/gui/widget_buddies.py:63 msgid "Empty" msgstr "" #: ../sdaps/gui/widget_buddies.py:75 ../sdaps/gui/widget_buddies.py:105 msgid "Questionnaire ID: " msgstr "" #: ../sdaps/image/__init__.py:47 msgid "" "It appears you have not build the C extension. Please run \"./setup.py build" "\" in the toplevel directory." msgstr "" #: ../sdaps/utils/latex.py:29 msgid "" "The latex character map is missing! Please build it using the supplied tool " "(create-latexmap.py)." msgstr "" #: ../sdaps/utils/latex.py:69 msgid "" "Generated string for LaTeX contains unicode characters. This may not work " "correctly and could mean the LaTeX character map needs to be updated." msgstr "" #: ../sdaps/utils/opencv.py:35 msgid "Cannot convert PDF files as poppler is not installed or usable!" msgstr "" #: ../sdaps/utils/opencv.py:44 msgid "File does not exist" msgstr "" #. The old code used to first filter, and then run; but that is #. a bit ineffective in a way #: ../sdaps/model/survey.py:386 #, python-format msgid "%i sheet" msgid_plural "%i sheets" msgstr[0] "" msgstr[1] "" #: ../sdaps/model/survey.py:402 #, python-format msgid "Processed %i of %i sheets, took %f seconds" msgstr "" #: ../sdaps/model/survey.py:449 msgid "" "A questionnaire that is printed in duplex needs an even amount of pages!" msgstr "" #: ../sdaps/model/survey.py:453 msgid "" "The 'classic' style only supports a maximum of six pages! Use the 'code128' " "style if you require more pages." msgstr "" #: ../sdaps/model/survey.py:466 msgid "IDs need to be integers in \"classic\" style!" msgstr "" #: ../sdaps/model/survey.py:472 #, python-format msgid "Invalid character %s in questionnaire ID \"%s\" in \"code128\" style!" msgstr "" #: ../sdaps/model/survey.py:476 msgid "" "SDAPS cannot draw a questionnaire ID with the \"custom\" style. Do this " "yourself somehow!" msgstr "" #. in simplex mode every page will have a matrix; it might be a None #. matrix though #: ../sdaps/recognize/buddies.py:71 #, python-format msgid "%s, %i: Matrix not recognized." msgstr "" #: ../sdaps/recognize/buddies.py:80 #, python-format msgid "%s, %i: Rotation not found." msgstr "" #. Copy the rotation over (if required) and print warning if the rotation is unknown #: ../sdaps/recognize/buddies.py:84 #, python-format msgid "Neither %s, %i or %s, %i has a known rotation!" msgstr "" #: ../sdaps/recognize/buddies.py:96 #, python-format msgid "%s, %i: Matrix not recognized (again)." msgstr "" #: ../sdaps/recognize/buddies.py:110 #, python-format msgid "%s, %i: Could not get page number." msgstr "" #. Whoa, that should not happen. #: ../sdaps/recognize/buddies.py:130 #, python-format msgid "Neither %s, %i or %s, %i has a known page number!" msgstr "" #. We don't touch the ignore flag in this case #. Simply print a message as this should *never* happen #: ../sdaps/recognize/buddies.py:141 #, python-format msgid "" "Got a simplex document where two adjacent pages had a known page number. " "This should never happen as even simplex scans are converted to duplex by " "inserting dummy pages. Maybe you did a simplex scan but added it in duplex " "mode? The pages in question are %s, %i and %s, %i." msgstr "" #: ../sdaps/recognize/buddies.py:158 #, python-format msgid "Images %s, %i and %s, %i do not have consecutive page numbers!" msgstr "" #: ../sdaps/recognize/buddies.py:174 #, python-format msgid "No page number for page %s, %i exists." msgstr "" #: ../sdaps/recognize/buddies.py:179 #, python-format msgid "Page number for page %s, %i already used by another image." msgstr "" #: ../sdaps/recognize/buddies.py:185 #, python-format msgid "Page number %i for page %s, %i is out of range." msgstr "" #: ../sdaps/recognize/buddies.py:202 #, python-format msgid "%s, %i: Could not read survey ID, but should be able to." msgstr "" #: ../sdaps/recognize/buddies.py:206 #, python-format msgid "Could not read survey ID of either %s, %i or %s, %i!" msgstr "" #. Broken survey ID ... #: ../sdaps/recognize/buddies.py:213 #, python-format msgid "Got a wrong survey ID (%s, %i)! It is %s, but should be %i." msgstr "" #: ../sdaps/recognize/buddies.py:235 #, python-format msgid "%s, %i: Could not read questionnaire ID, but should be able to." msgstr "" #: ../sdaps/recognize/buddies.py:241 #, python-format msgid "Could not read questionnaire ID of either %s, %i or %s, %i!" msgstr "" #: ../sdaps/recognize/buddies.py:271 msgid "" "Got different IDs on different pages for at least one sheet! Do *NOT* try to " "use filters with this survey! You have to run a \"reorder\" step for this to " "work properly!" msgstr "" #: ../sdaps/recognize/buddies.py:326 msgid "No style buddy loaded. This needs to be done for the \"custom\" style!" msgstr "" #: ../sdaps/report/answers.py:188 #, python-format msgid "Answers: %i" msgstr "" #: ../sdaps/report/answers.py:190 #, python-format msgid "Mean: %.2f" msgstr "" #: ../sdaps/report/answers.py:192 #, python-format msgid "Standard Deviation: %.2f" msgstr "" #: ../sdaps/report/__init__.py:75 ../sdaps/reporttex/__init__.py:140 msgid "Turned in Questionnaires" msgstr "" #: ../sdaps/report/__init__.py:92 ../sdaps/reporttex/__init__.py:139 msgid "sdaps report" msgstr "" #: ../sdaps/reset/__init__.py:29 msgid "Removing stored data..." msgstr "" #: ../sdaps/setup/buddies.py:62 #, python-format msgid "Head %(l0)i got no title." msgstr "" #: ../sdaps/setup/buddies.py:74 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no question." msgstr "" #: ../sdaps/setup/buddies.py:114 #, python-format msgid "Error in question \"%s\"" msgstr "" #: ../sdaps/setup/buddies.py:118 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no boxes." msgstr "" #: ../sdaps/setup/buddies.py:167 #, python-format msgid "%(class)s %(l0)i.%(l1)i lower box out of range." msgstr "" #: ../sdaps/setup/buddies.py:172 #, python-format msgid "%(class)s %(l0)i.%(l1)i upper box out of range." msgstr "" #: ../sdaps/setup/buddies.py:177 #, python-format msgid "%(class)s %(l0)i.%(l1)i lower box not before upper box." msgstr "" #: ../sdaps/setup/buddies.py:213 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly two answers." msgstr "" #: ../sdaps/setup/buddies.py:234 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly one box." msgstr "" #: ../sdaps/stamp/__init__.py:38 msgid "" "You may not specify the number of sheets for this survey. All questionnaires " "will be identical as the survey has been configured to not use questionnaire " "IDs for each sheet." msgstr "" #: ../sdaps/stamp/__init__.py:76 msgid "" "This survey has been configured to use questionnaire IDs. Each questionnaire " "will be unique. You need to use on of the options to add new IDs or use the " "existing ones." msgstr "" #: ../sdaps/stamp/latex.py:18 msgid "" "There should be no need to stamp a SDAPS Project that uses LaTeX and does " "not have different questionnaire IDs printed on each sheet.\n" "I am going to do so anyways." msgstr "" #: ../sdaps/stamp/latex.py:26 #, python-format msgid "Running %s now twice to generate the stamped questionnaire." msgstr "" #: ../sdaps/stamp/latex.py:30 ../sdaps/setuptex/__init__.py:107 #: ../sdaps/setuptex/__init__.py:148 ../sdaps/reporttex/__init__.py:162 #, python-format msgid "Error running \"%s\" to compile the LaTeX file." msgstr "" #: ../sdaps/stamp/latex.py:36 #, python-format msgid "" "An error occured during creation of the report. Temporary files left in '%s'." msgstr "" #: ../sdaps/setuptex/__init__.py:46 msgid "The survey directory already exists." msgstr "" #: ../sdaps/setuptex/__init__.py:51 #, python-format msgid "Unknown file type (%s). questionnaire_tex should be of type text/x-tex." msgstr "" #: ../sdaps/setuptex/__init__.py:52 msgid "Will keep going, but expect failure!" msgstr "" #: ../sdaps/setuptex/__init__.py:57 #, python-format msgid "Unknown file type (%s). additionalqobjects should be text/plain." msgstr "" #: ../sdaps/setuptex/__init__.py:103 ../sdaps/setuptex/__init__.py:143 #, python-format msgid "Running %s now twice to generate the questionnaire." msgstr "" #: ../sdaps/setuptex/__init__.py:122 msgid "Caught an Exception while parsing the SDAPS file. The current state is:" msgstr "" #: ../sdaps/setuptex/__init__.py:136 msgid "" "Some combination of options and project properties do not work. Aborted " "Setup." msgstr "" #: ../sdaps/setuptex/__init__.py:162 msgid "" "An error occured in the setup routine. The survey directory still exists. " "You can for example check the questionnaire.log file for LaTeX compile " "errors." msgstr "" #: ../sdaps/reporttex/__init__.py:107 msgid "author|Unknown" msgstr "" #: ../sdaps/reporttex/__init__.py:138 msgid "tex language|english" msgstr "" #: ../sdaps/reporttex/__init__.py:155 #, python-format msgid "The TeX project with the report data is located at '%s'." msgstr "" #: ../sdaps/reporttex/__init__.py:158 #, python-format msgid "Running %s now twice to generate the report." msgstr "" #: ../sdaps/reporttex/__init__.py:168 #, python-format msgid "An occured during creation of the report. Temporary files left in '%s'." msgstr "" sdaps-1.9.8/po/fr.po0000644000175000000660000007676413611116355015012 0ustar benjaminlock00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: SDAPS 0.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:10+0100\n" "PO-Revision-Date: 2020-01-05 19:21+0000\n" "Last-Translator: Nathan \n" "Language-Team: French " "\n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" "X-Generator: Weblate 3.10\n" #: ../sdaps/script.py:41 msgid "SDAPS -- Paper based survey tool." msgstr "SDAPS - Outil d'enquête sur papier." #: ../sdaps/script.py:45 msgid "command list|Commands:" msgstr "liste de commandes|Commandes :" #: ../sdaps/script.py:50 msgid "project directory|The SDAPS project." msgstr "répertoire du projet|Le projet SDAPS." #: ../sdaps/add/__init__.py:55 #, python-format msgid "" "Invalid input file %s. You need to specify a (multipage) monochrome TIFF as " "input." msgstr "" "Fichier %s non valide. Veuillez spécifier une image au format TIFF " "monochrome (multipage) en entrée." #: ../sdaps/add/__init__.py:67 #, python-format msgid "" "Not adding %s because it has a wrong page count (needs to be a mulitple of " "%i)." msgstr "" "%s n'a pas été ajouté parce que le nombre de pages est incorrect (doit être " "un multiple de %i)." #: ../sdaps/boxgallery/__init__.py:108 #, python-format msgid "Rendering boxgallery for metric \"%s\"." msgstr "" #: ../sdaps/log.py:37 msgid "Warning: " msgstr "Avertissement : " #: ../sdaps/log.py:41 msgid "Error: " msgstr "Erreur : " #: ../sdaps/cmdline/add.py:31 msgid "Add scanned questionnaires to the survey." msgstr "Ajouter les questionnaires scannés à l'enquête." #: ../sdaps/cmdline/add.py:32 msgid "" "This command is used to add scanned images to the survey.\n" " The image data needs to be a (multipage) 300dpi monochrome TIFF file. " "You\n" " may choose not to copy the data into the project directory. In that " "case\n" " the data will be referenced using a relative path." msgstr "" "Cette commande sert à ajouter des images numérisées au sondage.\n" "\tLe fichier image doit être au format TIFF monochrome 300ppp (multipage). " "Vous\n" "\tpouvez choisir de ne pas copier le fichier dans le dossier du projet. Dans " "ce cas,\n" "\tvous devez indiquer son chemin relatif." #: ../sdaps/cmdline/add.py:38 msgid "Convert given files and add the result." msgstr "Convertir les fichiers donnés et ajouter le résultat." #: ../sdaps/cmdline/add.py:43 msgid "" "Do a 3D-transformation after finding the corner marks. If the\n" " corner marks are not found then the image will be added as-is." msgstr "" "Effectue une transformation 3D après avoir repéré les marques des coins. Si " "les\n" "\tmarques des coins ne sont pas trouvées l'image est ajoutée en l'état." #: ../sdaps/cmdline/add.py:49 msgid "" "Force adding the images even if the page count is wrong (only use if you " "know what you are doing)." msgstr "" "Ajouter les images même si le nombre de pages est incorrect (n'utilisez ceci " "que si vous savez ce que vous faites)." #: ../sdaps/cmdline/add.py:53 msgid "Copy the files into the directory (default)." msgstr "Copie les fichiers dans le répertoire (par défaut)." #: ../sdaps/cmdline/add.py:58 msgid "Do not copy the files into the directory." msgstr "Ne copie pas les fichiers dans le répertoire." #: ../sdaps/cmdline/add.py:62 msgid "" "Images contain a duplex scan of a simplex questionnaire (default: simplex " "scan)." msgstr "" "Les images contiennent un scan recto-verso d'un questionnaire en recto " "simple (par défaut : scan recto simple)." #: ../sdaps/cmdline/add.py:68 ../sdaps/cmdline/convert.py:48 msgid "A number of TIFF image files." msgstr "Un nombre de fichiers TIFF." #: ../sdaps/cmdline/add.py:94 msgid "The --no-copy option is not compatible with --convert!" msgstr "L'option --no-copy n'est pas compatible avec --convert !" #: ../sdaps/cmdline/add.py:103 msgid "Converting input files into a single temporary file." msgstr "Convertir les fichiers d'entrée dans un fichier temporaire unique." #: ../sdaps/cmdline/add.py:115 msgid "" "The page count of the created temporary file does not work with this survey." msgstr "" "Le nombre de pages du fichier temporaire n'est pas compatible avec ce " "sondage." #: ../sdaps/cmdline/add.py:120 msgid "Running the conversion failed." msgstr "La conversion a échoué." #: ../sdaps/cmdline/add.py:126 #, python-format msgid "Processing %s" msgstr "Traitement de %s" #: ../sdaps/cmdline/add.py:130 ../sdaps/reset/__init__.py:33 msgid "Done" msgstr "Fait" #: ../sdaps/cmdline/annotate.py:28 msgid "Annotate the questionnaire and show the recognized positions." msgstr "Annoter le questionnaire et montrer les positions reconnues." #: ../sdaps/cmdline/annotate.py:29 msgid "" "This command is mainly a debug utility. It creates an\n" " annotated version of the questionnaire, with the information that SDAPS\n" " knows about it overlayed on top." msgstr "" "Cette commande est principalement faite pour le débogage. Elle crée une\n" "\tversion du questionnaire annotée, comportant les informations \n" "\tconnues par SDAPS en surimpression." #: ../sdaps/cmdline/boxgallery.py:31 msgid "Create PDFs with boxes sorted by the detection heuristics." msgstr "Créer des PDF avec des cadres triés par les heuristiques de détection." #: ../sdaps/cmdline/boxgallery.py:32 msgid "" "SDAPS uses multiple heuristics to detect determine the\n" " state of checkboxes. There is a list for each heuristic giving the " "expected\n" " state and the quality of the value (see defs.py). Using this command a " "PDF\n" " will be created for each of the heuristics so that one can adjust the\n" " values." msgstr "" "SDAPS utilise plusieurs méthodes pour déterminer l'état d'une\n" "\tcase à cocher. Il y a une liste pour chacune d'elles donnant l'état\n" "\tattendu et la qualité du résultat (voir defs.py). Un fichier PDF\n" "\tsera généré pour chaque méthode pouvant influer sur le résultat." #: ../sdaps/cmdline/boxgallery.py:40 msgid "" "Reruns part of the recognition process and retrieves debug images from this " "step." msgstr "" "Réexécute une partie de l'algorithme de reconnaissance et récupère les " "images de débogage à partir de cette étape." #: ../sdaps/cmdline/convert.py:30 msgid "Convert a set of images to the correct image format." msgstr "Convertir un lot d'images dans le bon format." #: ../sdaps/cmdline/convert.py:31 #, fuzzy msgid "" "This command can be used if you scanned files in something\n" " other than the expected monochrome TIFF mode. All given files will\n" " be loaded, converted to monochrome and stored in a multipage 1bpp\n" " TIFF file. Optionally, you can select \"3D transformation\"\\ ,which " "may facilitate\n" " working with photos of questionnaires instead of scans." msgstr "" "Cette commande peut être utilisée si vous numérisez dans un autre\n" "\tformat que le TIFF monochrome. Tous les fichiers doivent être\n" "\tchargés et enregistrés dans un seul fichier TIFF monochrome (1bpp).\n" "\tPour travailler avec des photos des questionnaires il est possible \n" "\tde leur appliquer directement une transformation 3D." #: ../sdaps/cmdline/convert.py:38 #, fuzzy msgid "" "Do a 3D-transformation after finding the corner marks.\n" " If they are not found, the image will be processed as-is." msgstr "" "Effectuer une transformation 3D après avoir repéré les marques des coins. Si " "les\n" "\tmarques des coins ne sont pas trouvées l'image est ajoutée en l'état." #: ../sdaps/cmdline/convert.py:44 msgid "The location of the output file." msgstr "L'emplacement du fichier de sortie." #: ../sdaps/cmdline/convert.py:57 msgid "No output filename specified!" msgstr "Aucun nom de fichier de sortie n'est précisé !" #: ../sdaps/cmdline/cover.py:27 msgid "Create a cover for the questionnaires." msgstr "Créer une jaquette pour les questionnaires." #: ../sdaps/cmdline/cover.py:28 msgid "" "This command creates a cover page for questionnaires. All\n" " the metadata of the survey will be printed on the page." msgstr "" "Cette commande crée une jaquette pour les questionnaires. Toutes\n" "\tles métadonnées du sondage y seront imprimées." #: ../sdaps/cmdline/cover.py:31 #, python-format msgid "Filename to store the data to (default: cover_%%i.pdf)" msgstr "" "Nom de fichier pour le stockage des données (par défaut : cover_%%i.pdf)" #: ../sdaps/cmdline/csvdata.py:34 msgid "Import or export data to/from CSV files." msgstr "Importer ou exporter des données depuis ou vers un fichier CSV." #: ../sdaps/cmdline/csvdata.py:35 msgid "" "Import or export data to/from a CSV file. The first line\n" " is a header which defines questionnaire_id and global_id, and a column\n" " for each checkbox and textfield. Note that the import is currently very\n" " limited, as you need to specifiy the questionnaire ID to select the " "sheet\n" " which should be updated." msgstr "" "Importer ou exporter des données depuis ou vers un fichier CSV. La première\n" " ligne est un entête contenant questionnaire_id, global_id puis " "chaque case\n" "\t à cocher et champ de texte. Notez que l'importation est actuellement " "très\n" "\tlimitée ; vous devez indiquer l'identifiant du questionnaire pour choisir " "la fiche\n" "\tqui doit être mise à jour." #: ../sdaps/cmdline/csvdata.py:44 msgid "Export data to CSV file." msgstr "Exporter les données dans un fichiers CSV." #: ../sdaps/cmdline/csvdata.py:46 #, python-format msgid "Filename to store the data to (default: data_%%i.csv)" msgstr "Nom de fichier pour stocker les données (par défaut : data_%%i.csv)" #: ../sdaps/cmdline/csvdata.py:48 msgid "The delimiter used in the CSV file (default ',')" msgstr "Le délimiteur utilisé dans le fichier CSV (par défaut ',')" #: ../sdaps/cmdline/csvdata.py:52 ../sdaps/cmdline/report.py:31 #: ../sdaps/cmdline/reporttex.py:52 msgid "Filter to only export a partial dataset." msgstr "Filtrer pour exporter un jeu de données partiel." #: ../sdaps/cmdline/csvdata.py:54 msgid "Export images of freeform fields." msgstr "Exporter les images des champs libres." #: ../sdaps/cmdline/csvdata.py:60 msgid "Export an image for each question that includes all boxes." msgstr "Exporter une image pour chaque question qui inclut toutes les cases." #: ../sdaps/cmdline/csvdata.py:66 msgid "Export the recognition quality for each checkbox." msgstr "Exporter la qualité de la reconnaissance pour chaque case à cocher." #: ../sdaps/cmdline/csvdata.py:74 msgid "Import data to from a CSV file." msgstr "Importer des données depuis un fichier CSV." #: ../sdaps/cmdline/csvdata.py:76 msgid "The file to import." msgstr "Le fichier à importer." #: ../sdaps/cmdline/gui.py:28 msgid "Launch a GUI. You can view and alter the (recognized) answers with it." msgstr "" "Lancer une interface graphique. Vous pouvez y afficher et modifier les " "réponses (reconnues)." #: ../sdaps/cmdline/gui.py:29 msgid "" "This command launches a graphical user interface that can\n" " be used to correct answers. You need to run \"recognize\" before using " "it.\n" " " msgstr "" "Cette commande affiche une interface graphique qui permet\n" "\tde corriger une réponse. Auparavant, vous devez lancer la commande \"" "recognize\".\n" " " #: ../sdaps/cmdline/gui.py:34 msgid "Filter to only show a partial dataset." msgstr "Filtrer pour ne montrer qu'une partie des données." #: ../sdaps/cmdline/ids.py:29 msgid "Export and import questionnaire IDs." msgstr "Exportez et importez les identifiants des questionnaires." #: ../sdaps/cmdline/ids.py:30 msgid "" "This command can be used to import and export questionnaire\n" " IDs. It only makes sense in projects where such an ID is printed on the\n" " questionnaire. Note that you can also add IDs by using the stamp " "command,\n" " which will give you the PDF at the same time." msgstr "" "Cette commande peut être utilisée pour importer et exporter des\n" "\tID de questionnaire. Elle n'est pertinente que dans les projets où un ID " "est \n" "\timprimé sur les questionnaires. Vous pouvez également ajouter des ID à l’" "aide\n" "\tde la commande stamp, qui génère également le PDF.." #: ../sdaps/cmdline/ids.py:35 #, python-format msgid "Filename to store the data to (default: ids_%%i)" msgstr "Nom de fichier pour stocker les données (par défaut : ids_%%i)" #: ../sdaps/cmdline/ids.py:38 msgid "Add IDs to the internal list from the specified file." msgstr "Ajouter les IDs à partir du fichier spécifié." #: ../sdaps/cmdline/info.py:28 msgid "Display and modify metadata of project." msgstr "Affichez et modifiez les métadonnées du projet." #: ../sdaps/cmdline/info.py:29 msgid "" "This command lets you modify the metadata of the SDAPS\n" " project. You can modify, add and remove arbitrary keys that will be " "printed\n" " on the report. The only key that always exist is \"title\".\n" " If no key is given then a list of defined keys is printed." msgstr "" "Cette commande vous permet de modifier les métadonnées du projet \n" "\tSDAPS. Vous pouvez modifier, ajouter et supprimer toutes clés utiles \n" "\tqui seront imprimées sur le rapport. La seule clé qui existent toujours " "est « title ».\n" "\tSi aucune clé n’est donnée, une liste de clés définies est imprimée." #: ../sdaps/cmdline/info.py:36 msgid "Delete the key and value pair." msgstr "Supprimer la paire clé / valeur." #: ../sdaps/cmdline/info.py:40 msgid "The key to display or modify." msgstr "La clé à afficher ou modifier." #: ../sdaps/cmdline/info.py:44 msgid "Set the given key to this value." msgstr "La valeur à donner à cette clé." #: ../sdaps/cmdline/info.py:69 msgid "Existing fields:\n" msgstr "Champs existants :\n" #: ../sdaps/cmdline/recognize.py:28 msgid "Run the optical mark recognition." msgstr "Exécuter la reconnaissance optique de marques." #: ../sdaps/cmdline/recognize.py:29 msgid "" "Iterates over all images and runs the optical mark\n" " recognition. It will reevaluate sheets even if \"recognize\" has " "already\n" " run or manual changes were made." msgstr "" "Exécute la reconnaissance optique de marques pour chaque\n" "\timage. Les pages seront réévaluées, même si l'option recognize\n" "\ta déjà été exécutée ou si des modifications manuelles ont été apportées." #: ../sdaps/cmdline/recognize.py:34 msgid "" "Only identify the page properties, but don't recognize the checkbox states." msgstr "" "Identifie les propriétés de la page, sans reconnaître la valeur des cases à " "cocher." #: ../sdaps/cmdline/recognize.py:39 msgid "" "Rerun the recognition for all pages. The default is to skip all pages that " "were recognized or verified already." msgstr "" "Réexécute la reconnaissance pour chaque page. Par défaut, les pages déjà " "reconnues ou vérifiées sont sautées." #: ../sdaps/cmdline/reorder.py:26 msgid "Reorder pages according to questionnaire ID." msgstr "Retrie les pages par ID de questionnaire." #: ../sdaps/cmdline/reorder.py:27 msgid "" "This command reorders all pages according to the already\n" " recognized questionnaire ID. To use it add all the files to the " "project,\n" " then run a partial recognition using \"recognize --identify\". After " "this\n" " you have to run this command to reorder the data for the real " "recognition.\n" " " msgstr "" "Cette commander retrie toutes les pages par ID de questionnaire déjà\n" " reconnu. Pour l'utiliser, ajouter au projet tout les fichiers, puis " "exécuter\n" " une reconnaissance partiel avec « recognize --identify ». Enfin, " "exécuter\n" " cette commande pour trier les données avant la vraie reconnaissance.\n" " " #: ../sdaps/cmdline/report.py:26 msgid "Create a PDF report." msgstr "Créer un rapport PDF." #: ../sdaps/cmdline/report.py:27 msgid "" "This command creates a PDF report using reportlab that\n" " contains statistics and if selected the freeform fields." msgstr "" "Cette commande crée un rapport PDF avec reportlab contenant \n" " des statistiques et, si demandés, les champs libre." #: ../sdaps/cmdline/report.py:33 msgid "Create a filtered report for every checkbox." msgstr "Créer un rapport filtré pour chaque case." #: ../sdaps/cmdline/report.py:36 msgid "Short format (without freeform text fields)." msgstr "Format court (sans les champs de texte libre)." #: ../sdaps/cmdline/report.py:41 msgid "Detailed output. (default)" msgstr "Résultat détaillé (par défaut)" #: ../sdaps/cmdline/report.py:47 ../sdaps/cmdline/reporttex.py:30 msgid "" "Do not include original images in the report. This is useful if there are " "privacy concerns." msgstr "" "Exclure les image originale du rapport. Peut être utile pour des questions " "de confidentialité." #: ../sdaps/cmdline/report.py:52 ../sdaps/cmdline/reporttex.py:35 msgid "Do not use substitutions instead of images." msgstr "Ne pas substituer les images." #: ../sdaps/cmdline/report.py:58 ../sdaps/cmdline/reporttex.py:46 msgid "The paper size used for the output (default: locale dependent)" msgstr "Le format de page pour le résultat (par défaut selon la localité)" #: ../sdaps/cmdline/report.py:61 ../sdaps/cmdline/reporttex.py:49 #, python-format msgid "Filename to store the data to (default: report_%%i.pdf)" msgstr "Nom de fichier pour stocker les données (report_%%i.pdf par défaut)" #: ../sdaps/cmdline/reporttex.py:26 msgid "Create a PDF report using LaTeX." msgstr "Créer un rapport PDF avec LaTex." #: ../sdaps/cmdline/reporttex.py:27 msgid "" "This command creates a PDF report using LaTeX that\n" " contains statistics and freeform fields." msgstr "" "Cette commande crée un rapport PDF avec LaTex\n" " contenant des stats et les champs libres." #: ../sdaps/cmdline/reporttex.py:41 msgid "Save the generated TeX files instead of the final PDF." msgstr "Enregistrer les fichiers Tex générés au lieu du PDF final." #: ../sdaps/cmdline/reset.py:26 msgid "Reset project into original state" msgstr "Rétablir le projet à son état initial" #: ../sdaps/cmdline/reset.py:27 msgid "" "This command does a full reset of the project. All data\n" " will be discarded and only the empty project is left.\n" " " msgstr "" "Cette commande réinitialise complètement le projet.\n" " Toute donnée sera perdue excepté le projet vide.\n" " " #: ../sdaps/cmdline/setup.py:27 msgid "Create a new survey using a LaTeX document." msgstr "" #: ../sdaps/cmdline/setup.py:28 msgid "" "Create a new survey from a LaTeX document. You need to\n" " be using the SDAPS class. All the metadata and options for the project\n" " can be set inside the LaTeX document." msgstr "" #: ../sdaps/cmdline/setup.py:33 msgid "The LaTeX Document" msgstr "" #: ../sdaps/cmdline/setup.py:35 msgid "" "Additional files that are required by the LaTeX document and need to be " "copied into the project directory." msgstr "" #: ../sdaps/cmdline/setup.py:39 msgid "Additional questions that are not part of the questionnaire." msgstr "" #: ../sdaps/cmdline/stamp.py:26 msgid "Add marks for automatic processing." msgstr "" #: ../sdaps/cmdline/stamp.py:27 msgid "" "This command creates the printable document. Depending on\n" " the projects setting you are required to specifiy a source for " "questionnaire\n" " IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:33 msgid "" "If using questionnaire IDs, create N questionnaires with randomized IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:36 msgid "" "If using questionnaire IDs, create questionnaires from the IDs read from the " "specified file." msgstr "" #: ../sdaps/cmdline/stamp.py:39 msgid "If using questionnaire IDs, create questionnaires for all stored IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:42 #, python-format msgid "Filename to store the data to (default: stamp_%%i.pdf)" msgstr "" #: ../sdaps/convert/__init__.py:37 #, python-format msgid "Could not apply 3D-transformation to image '%s', page %i!" msgstr "" #: ../sdaps/cover/__init__.py:40 msgid "SDAPS questionnaire" msgstr "" #: ../sdaps/csvdata/buddies.py:77 #, fuzzy, python-format msgid "Not importing unknown questionnaire ID \"%s\"" msgstr "Exportez et importez les identifiants des questionnaires." #: ../sdaps/gui/__init__.py:59 msgid "" "The survey does not have any images! Please add images (and run recognize) " "before using the GUI." msgstr "" #: ../sdaps/gui/__init__.py:211 msgid "Page|Invalid" msgstr "" #: ../sdaps/gui/__init__.py:214 #, python-format msgid "Page %i" msgid_plural "Page %i" msgstr[0] "" msgstr[1] "" #: ../sdaps/gui/__init__.py:256 msgid "Copyright © 2007-2014 The SDAPS Authors" msgstr "" #: ../sdaps/gui/__init__.py:258 msgid "Scripts for data acquisition with paper based surveys" msgstr "" #: ../sdaps/gui/__init__.py:259 msgid "http://sdaps.org" msgstr "" #: ../sdaps/gui/__init__.py:260 msgid "translator-credits" msgstr "" #: ../sdaps/gui/__init__.py:305 #, python-format msgid " of %i" msgstr "" #: ../sdaps/gui/__init__.py:306 #, python-format msgid "Recognition Quality: %.2f" msgstr "" #: ../sdaps/gui/__init__.py:322 msgid "" "You have reached the first page of the survey. Would you like to go to the " "last page?" msgstr "" #: ../sdaps/gui/__init__.py:324 msgid "Go to last page" msgstr "" #: ../sdaps/gui/__init__.py:346 msgid "" "You have reached the last page of the survey. Would you like to go to the " "first page?" msgstr "" #: ../sdaps/gui/__init__.py:348 msgid "Go to first page" msgstr "" #: ../sdaps/gui/__init__.py:457 msgid "Close without saving" msgstr "" #: ../sdaps/gui/__init__.py:461 msgid "" "Save the project before closing?\n" "\n" "If you do not save you may loose data." msgstr "" #: ../sdaps/gui/main_window.ui.h:1 msgid "Forward" msgstr "" #: ../sdaps/gui/main_window.ui.h:2 msgid "Previous" msgstr "" #: ../sdaps/gui/main_window.ui.h:3 msgid "Zoom In" msgstr "" #: ../sdaps/gui/main_window.ui.h:4 msgid "Zoom Out" msgstr "" #: ../sdaps/gui/main_window.ui.h:5 msgid "SDAPS" msgstr "" #: ../sdaps/gui/main_window.ui.h:6 msgid "_File" msgstr "" #: ../sdaps/gui/main_window.ui.h:7 msgid "_View" msgstr "" #: ../sdaps/gui/main_window.ui.h:8 msgid "_Help" msgstr "" #: ../sdaps/gui/main_window.ui.h:9 msgid "Page Rotated" msgstr "" #: ../sdaps/gui/main_window.ui.h:10 msgid "Sort by Quality" msgstr "" #: ../sdaps/gui/main_window.ui.h:11 msgid "label" msgstr "" #: ../sdaps/gui/widget_buddies.py:56 msgid "Global Properties" msgstr "" #: ../sdaps/gui/widget_buddies.py:60 msgid "Sheet valid" msgstr "" #: ../sdaps/gui/widget_buddies.py:61 msgid "Sheet Verified" msgstr "" #: ../sdaps/gui/widget_buddies.py:62 msgid "Page Verified" msgstr "" #: ../sdaps/gui/widget_buddies.py:63 msgid "Empty" msgstr "" #: ../sdaps/gui/widget_buddies.py:75 ../sdaps/gui/widget_buddies.py:105 msgid "Questionnaire ID: " msgstr "" #: ../sdaps/image/__init__.py:47 msgid "" "It appears you have not build the C extension. Please run \"./setup.py build" "\" in the toplevel directory." msgstr "" #: ../sdaps/utils/latex.py:29 msgid "" "The latex character map is missing! Please build it using the supplied tool " "(create-latexmap.py)." msgstr "" #: ../sdaps/utils/latex.py:69 msgid "" "Generated string for LaTeX contains unicode characters. This may not work " "correctly and could mean the LaTeX character map needs to be updated." msgstr "" #: ../sdaps/utils/opencv.py:35 msgid "Cannot convert PDF files as poppler is not installed or usable!" msgstr "" #: ../sdaps/utils/opencv.py:44 msgid "File does not exist" msgstr "" #. The old code used to first filter, and then run; but that is #. a bit ineffective in a way #: ../sdaps/model/survey.py:386 #, python-format msgid "%i sheet" msgid_plural "%i sheets" msgstr[0] "" msgstr[1] "" #: ../sdaps/model/survey.py:402 #, python-format msgid "Processed %i of %i sheets, took %f seconds" msgstr "" #: ../sdaps/model/survey.py:449 msgid "" "A questionnaire that is printed in duplex needs an even amount of pages!" msgstr "" #: ../sdaps/model/survey.py:453 msgid "" "The 'classic' style only supports a maximum of six pages! Use the 'code128' " "style if you require more pages." msgstr "" #: ../sdaps/model/survey.py:466 msgid "IDs need to be integers in \"classic\" style!" msgstr "" #: ../sdaps/model/survey.py:472 #, python-format msgid "Invalid character %s in questionnaire ID \"%s\" in \"code128\" style!" msgstr "" #: ../sdaps/model/survey.py:476 msgid "" "SDAPS cannot draw a questionnaire ID with the \"custom\" style. Do this " "yourself somehow!" msgstr "" #. in simplex mode every page will have a matrix; it might be a None #. matrix though #: ../sdaps/recognize/buddies.py:71 #, python-format msgid "%s, %i: Matrix not recognized." msgstr "" #: ../sdaps/recognize/buddies.py:80 #, python-format msgid "%s, %i: Rotation not found." msgstr "" #. Copy the rotation over (if required) and print warning if the rotation is unknown #: ../sdaps/recognize/buddies.py:84 #, python-format msgid "Neither %s, %i or %s, %i has a known rotation!" msgstr "" #: ../sdaps/recognize/buddies.py:96 #, python-format msgid "%s, %i: Matrix not recognized (again)." msgstr "" #: ../sdaps/recognize/buddies.py:110 #, python-format msgid "%s, %i: Could not get page number." msgstr "" #. Whoa, that should not happen. #: ../sdaps/recognize/buddies.py:130 #, python-format msgid "Neither %s, %i or %s, %i has a known page number!" msgstr "" #. We don't touch the ignore flag in this case #. Simply print a message as this should *never* happen #: ../sdaps/recognize/buddies.py:141 #, python-format msgid "" "Got a simplex document where two adjacent pages had a known page number. " "This should never happen as even simplex scans are converted to duplex by " "inserting dummy pages. Maybe you did a simplex scan but added it in duplex " "mode? The pages in question are %s, %i and %s, %i." msgstr "" #: ../sdaps/recognize/buddies.py:158 #, python-format msgid "Images %s, %i and %s, %i do not have consecutive page numbers!" msgstr "" #: ../sdaps/recognize/buddies.py:174 #, python-format msgid "No page number for page %s, %i exists." msgstr "" #: ../sdaps/recognize/buddies.py:179 #, python-format msgid "Page number for page %s, %i already used by another image." msgstr "" #: ../sdaps/recognize/buddies.py:185 #, python-format msgid "Page number %i for page %s, %i is out of range." msgstr "" #: ../sdaps/recognize/buddies.py:202 #, python-format msgid "%s, %i: Could not read survey ID, but should be able to." msgstr "" #: ../sdaps/recognize/buddies.py:206 #, python-format msgid "Could not read survey ID of either %s, %i or %s, %i!" msgstr "" #. Broken survey ID ... #: ../sdaps/recognize/buddies.py:213 #, python-format msgid "Got a wrong survey ID (%s, %i)! It is %s, but should be %i." msgstr "" #: ../sdaps/recognize/buddies.py:235 #, python-format msgid "%s, %i: Could not read questionnaire ID, but should be able to." msgstr "" #: ../sdaps/recognize/buddies.py:241 #, python-format msgid "Could not read questionnaire ID of either %s, %i or %s, %i!" msgstr "" #: ../sdaps/recognize/buddies.py:271 msgid "" "Got different IDs on different pages for at least one sheet! Do *NOT* try to " "use filters with this survey! You have to run a \"reorder\" step for this to " "work properly!" msgstr "" #: ../sdaps/recognize/buddies.py:326 msgid "No style buddy loaded. This needs to be done for the \"custom\" style!" msgstr "" #: ../sdaps/report/answers.py:188 #, python-format msgid "Answers: %i" msgstr "" #: ../sdaps/report/answers.py:190 #, python-format msgid "Mean: %.2f" msgstr "" #: ../sdaps/report/answers.py:192 #, python-format msgid "Standard Deviation: %.2f" msgstr "" #: ../sdaps/report/__init__.py:75 ../sdaps/reporttex/__init__.py:140 msgid "Turned in Questionnaires" msgstr "" #: ../sdaps/report/__init__.py:92 ../sdaps/reporttex/__init__.py:139 msgid "sdaps report" msgstr "" #: ../sdaps/reset/__init__.py:29 msgid "Removing stored data..." msgstr "" #: ../sdaps/setup/buddies.py:62 #, python-format msgid "Head %(l0)i got no title." msgstr "" #: ../sdaps/setup/buddies.py:74 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no question." msgstr "" #: ../sdaps/setup/buddies.py:114 #, python-format msgid "Error in question \"%s\"" msgstr "" #: ../sdaps/setup/buddies.py:118 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no boxes." msgstr "" #: ../sdaps/setup/buddies.py:167 #, python-format msgid "%(class)s %(l0)i.%(l1)i lower box out of range." msgstr "" #: ../sdaps/setup/buddies.py:172 #, python-format msgid "%(class)s %(l0)i.%(l1)i upper box out of range." msgstr "" #: ../sdaps/setup/buddies.py:177 #, python-format msgid "%(class)s %(l0)i.%(l1)i lower box not before upper box." msgstr "" #: ../sdaps/setup/buddies.py:213 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly two answers." msgstr "" #: ../sdaps/setup/buddies.py:234 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly one box." msgstr "" #: ../sdaps/stamp/__init__.py:38 msgid "" "You may not specify the number of sheets for this survey. All questionnaires " "will be identical as the survey has been configured to not use questionnaire " "IDs for each sheet." msgstr "" #: ../sdaps/stamp/__init__.py:76 msgid "" "This survey has been configured to use questionnaire IDs. Each questionnaire " "will be unique. You need to use on of the options to add new IDs or use the " "existing ones." msgstr "" #: ../sdaps/stamp/latex.py:18 msgid "" "There should be no need to stamp a SDAPS Project that uses LaTeX and does " "not have different questionnaire IDs printed on each sheet.\n" "I am going to do so anyways." msgstr "" #: ../sdaps/stamp/latex.py:26 #, python-format msgid "Running %s now twice to generate the stamped questionnaire." msgstr "" #: ../sdaps/stamp/latex.py:30 ../sdaps/setuptex/__init__.py:107 #: ../sdaps/setuptex/__init__.py:148 ../sdaps/reporttex/__init__.py:162 #, python-format msgid "Error running \"%s\" to compile the LaTeX file." msgstr "" #: ../sdaps/stamp/latex.py:36 #, python-format msgid "" "An error occured during creation of the report. Temporary files left in '%s'." msgstr "" #: ../sdaps/setuptex/__init__.py:46 msgid "The survey directory already exists." msgstr "" #: ../sdaps/setuptex/__init__.py:51 #, python-format msgid "Unknown file type (%s). questionnaire_tex should be of type text/x-tex." msgstr "" #: ../sdaps/setuptex/__init__.py:52 msgid "Will keep going, but expect failure!" msgstr "" #: ../sdaps/setuptex/__init__.py:57 #, python-format msgid "Unknown file type (%s). additionalqobjects should be text/plain." msgstr "" #: ../sdaps/setuptex/__init__.py:103 ../sdaps/setuptex/__init__.py:143 #, python-format msgid "Running %s now twice to generate the questionnaire." msgstr "" #: ../sdaps/setuptex/__init__.py:122 msgid "Caught an Exception while parsing the SDAPS file. The current state is:" msgstr "" #: ../sdaps/setuptex/__init__.py:136 msgid "" "Some combination of options and project properties do not work. Aborted " "Setup." msgstr "" #: ../sdaps/setuptex/__init__.py:162 msgid "" "An error occured in the setup routine. The survey directory still exists. " "You can for example check the questionnaire.log file for LaTeX compile " "errors." msgstr "" #: ../sdaps/reporttex/__init__.py:107 msgid "author|Unknown" msgstr "" #: ../sdaps/reporttex/__init__.py:138 msgid "tex language|english" msgstr "" #: ../sdaps/reporttex/__init__.py:155 #, python-format msgid "The TeX project with the report data is located at '%s'." msgstr "" #: ../sdaps/reporttex/__init__.py:158 #, python-format msgid "Running %s now twice to generate the report." msgstr "" #: ../sdaps/reporttex/__init__.py:168 #, python-format msgid "An occured during creation of the report. Temporary files left in '%s'." msgstr "" sdaps-1.9.8/po/it.po0000644000175000000660000006062313410742232014776 0ustar benjaminlock00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:10+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../sdaps/script.py:41 msgid "SDAPS -- Paper based survey tool." msgstr "" #: ../sdaps/script.py:45 msgid "command list|Commands:" msgstr "" #: ../sdaps/script.py:50 msgid "project directory|The SDAPS project." msgstr "" #: ../sdaps/add/__init__.py:55 #, python-format msgid "" "Invalid input file %s. You need to specify a (multipage) monochrome TIFF as " "input." msgstr "" #: ../sdaps/add/__init__.py:67 #, python-format msgid "" "Not adding %s because it has a wrong page count (needs to be a mulitple of " "%i)." msgstr "" #: ../sdaps/boxgallery/__init__.py:108 #, python-format msgid "Rendering boxgallery for metric \"%s\"." msgstr "" #: ../sdaps/log.py:37 msgid "Warning: " msgstr "" #: ../sdaps/log.py:41 msgid "Error: " msgstr "" #: ../sdaps/cmdline/add.py:31 msgid "Add scanned questionnaires to the survey." msgstr "" #: ../sdaps/cmdline/add.py:32 msgid "" "This command is used to add scanned images to the survey.\n" " The image data needs to be a (multipage) 300dpi monochrome TIFF file. " "You\n" " may choose not to copy the data into the project directory. In that " "case\n" " the data will be referenced using a relative path." msgstr "" #: ../sdaps/cmdline/add.py:38 msgid "Convert given files and add the result." msgstr "" #: ../sdaps/cmdline/add.py:43 msgid "" "Do a 3D-transformation after finding the corner marks. If the\n" " corner marks are not found then the image will be added as-is." msgstr "" #: ../sdaps/cmdline/add.py:49 msgid "" "Force adding the images even if the page count is wrong (only use if you " "know what you are doing)." msgstr "" #: ../sdaps/cmdline/add.py:53 msgid "Copy the files into the directory (default)." msgstr "" #: ../sdaps/cmdline/add.py:58 msgid "Do not copy the files into the directory." msgstr "" #: ../sdaps/cmdline/add.py:62 msgid "" "Images contain a duplex scan of a simplex questionnaire (default: simplex " "scan)." msgstr "" #: ../sdaps/cmdline/add.py:68 ../sdaps/cmdline/convert.py:48 msgid "A number of TIFF image files." msgstr "" #: ../sdaps/cmdline/add.py:94 msgid "The --no-copy option is not compatible with --convert!" msgstr "" #: ../sdaps/cmdline/add.py:103 msgid "Converting input files into a single temporary file." msgstr "" #: ../sdaps/cmdline/add.py:115 msgid "" "The page count of the created temporary file does not work with this survey." msgstr "" #: ../sdaps/cmdline/add.py:120 msgid "Running the conversion failed." msgstr "" #: ../sdaps/cmdline/add.py:126 #, python-format msgid "Processing %s" msgstr "" #: ../sdaps/cmdline/add.py:130 ../sdaps/reset/__init__.py:33 msgid "Done" msgstr "" #: ../sdaps/cmdline/annotate.py:28 msgid "Annotate the questionnaire and show the recognized positions." msgstr "" #: ../sdaps/cmdline/annotate.py:29 msgid "" "This command is mainly a debug utility. It creates an\n" " annotated version of the questionnaire, with the information that SDAPS\n" " knows about it overlayed on top." msgstr "" #: ../sdaps/cmdline/boxgallery.py:31 msgid "Create PDFs with boxes sorted by the detection heuristics." msgstr "" #: ../sdaps/cmdline/boxgallery.py:32 msgid "" "SDAPS uses multiple heuristics to detect determine the\n" " state of checkboxes. There is a list for each heuristic giving the " "expected\n" " state and the quality of the value (see defs.py). Using this command a " "PDF\n" " will be created for each of the heuristics so that one can adjust the\n" " values." msgstr "" #: ../sdaps/cmdline/boxgallery.py:40 msgid "" "Reruns part of the recognition process and retrieves debug images from this " "step." msgstr "" #: ../sdaps/cmdline/convert.py:30 msgid "Convert a set of images to the correct image format." msgstr "" #: ../sdaps/cmdline/convert.py:31 msgid "" "This command can be used if you scanned files in something\n" " other than the expected monochrome TIFF mode. All given files will\n" " be loaded, converted to monochrome and stored in a multipage 1bpp\n" " TIFF file. Optionally, you can select \"3D transformation\"\\ ,which " "may facilitate\n" " working with photos of questionnaires instead of scans." msgstr "" #: ../sdaps/cmdline/convert.py:38 msgid "" "Do a 3D-transformation after finding the corner marks.\n" " If they are not found, the image will be processed as-is." msgstr "" #: ../sdaps/cmdline/convert.py:44 msgid "The location of the output file." msgstr "" #: ../sdaps/cmdline/convert.py:57 msgid "No output filename specified!" msgstr "" #: ../sdaps/cmdline/cover.py:27 msgid "Create a cover for the questionnaires." msgstr "" #: ../sdaps/cmdline/cover.py:28 msgid "" "This command creates a cover page for questionnaires. All\n" " the metadata of the survey will be printed on the page." msgstr "" #: ../sdaps/cmdline/cover.py:31 #, python-format msgid "Filename to store the data to (default: cover_%%i.pdf)" msgstr "" #: ../sdaps/cmdline/csvdata.py:34 msgid "Import or export data to/from CSV files." msgstr "" #: ../sdaps/cmdline/csvdata.py:35 msgid "" "Import or export data to/from a CSV file. The first line\n" " is a header which defines questionnaire_id and global_id, and a column\n" " for each checkbox and textfield. Note that the import is currently very\n" " limited, as you need to specifiy the questionnaire ID to select the " "sheet\n" " which should be updated." msgstr "" #: ../sdaps/cmdline/csvdata.py:44 msgid "Export data to CSV file." msgstr "" #: ../sdaps/cmdline/csvdata.py:46 #, python-format msgid "Filename to store the data to (default: data_%%i.csv)" msgstr "" #: ../sdaps/cmdline/csvdata.py:48 msgid "The delimiter used in the CSV file (default ',')" msgstr "" #: ../sdaps/cmdline/csvdata.py:52 ../sdaps/cmdline/report.py:31 #: ../sdaps/cmdline/reporttex.py:52 msgid "Filter to only export a partial dataset." msgstr "" #: ../sdaps/cmdline/csvdata.py:54 msgid "Export images of freeform fields." msgstr "" #: ../sdaps/cmdline/csvdata.py:60 msgid "Export an image for each question that includes all boxes." msgstr "" #: ../sdaps/cmdline/csvdata.py:66 msgid "Export the recognition quality for each checkbox." msgstr "" #: ../sdaps/cmdline/csvdata.py:74 msgid "Import data to from a CSV file." msgstr "" #: ../sdaps/cmdline/csvdata.py:76 msgid "The file to import." msgstr "" #: ../sdaps/cmdline/gui.py:28 msgid "Launch a GUI. You can view and alter the (recognized) answers with it." msgstr "" #: ../sdaps/cmdline/gui.py:29 msgid "" "This command launches a graphical user interface that can\n" " be used to correct answers. You need to run \"recognize\" before using " "it.\n" " " msgstr "" #: ../sdaps/cmdline/gui.py:34 msgid "Filter to only show a partial dataset." msgstr "" #: ../sdaps/cmdline/ids.py:29 msgid "Export and import questionnaire IDs." msgstr "" #: ../sdaps/cmdline/ids.py:30 msgid "" "This command can be used to import and export questionnaire\n" " IDs. It only makes sense in projects where such an ID is printed on the\n" " questionnaire. Note that you can also add IDs by using the stamp " "command,\n" " which will give you the PDF at the same time." msgstr "" #: ../sdaps/cmdline/ids.py:35 #, python-format msgid "Filename to store the data to (default: ids_%%i)" msgstr "" #: ../sdaps/cmdline/ids.py:38 msgid "Add IDs to the internal list from the specified file." msgstr "" #: ../sdaps/cmdline/info.py:28 msgid "Display and modify metadata of project." msgstr "" #: ../sdaps/cmdline/info.py:29 msgid "" "This command lets you modify the metadata of the SDAPS\n" " project. You can modify, add and remove arbitrary keys that will be " "printed\n" " on the report. The only key that always exist is \"title\".\n" " If no key is given then a list of defined keys is printed." msgstr "" #: ../sdaps/cmdline/info.py:36 msgid "Delete the key and value pair." msgstr "" #: ../sdaps/cmdline/info.py:40 msgid "The key to display or modify." msgstr "" #: ../sdaps/cmdline/info.py:44 msgid "Set the given key to this value." msgstr "" #: ../sdaps/cmdline/info.py:69 msgid "Existing fields:\n" msgstr "" #: ../sdaps/cmdline/recognize.py:28 msgid "Run the optical mark recognition." msgstr "" #: ../sdaps/cmdline/recognize.py:29 msgid "" "Iterates over all images and runs the optical mark\n" " recognition. It will reevaluate sheets even if \"recognize\" has " "already\n" " run or manual changes were made." msgstr "" #: ../sdaps/cmdline/recognize.py:34 msgid "" "Only identify the page properties, but don't recognize the checkbox states." msgstr "" #: ../sdaps/cmdline/recognize.py:39 msgid "" "Rerun the recognition for all pages. The default is to skip all pages that " "were recognized or verified already." msgstr "" #: ../sdaps/cmdline/reorder.py:26 msgid "Reorder pages according to questionnaire ID." msgstr "" #: ../sdaps/cmdline/reorder.py:27 msgid "" "This command reorders all pages according to the already\n" " recognized questionnaire ID. To use it add all the files to the " "project,\n" " then run a partial recognition using \"recognize --identify\". After " "this\n" " you have to run this command to reorder the data for the real " "recognition.\n" " " msgstr "" #: ../sdaps/cmdline/report.py:26 msgid "Create a PDF report." msgstr "" #: ../sdaps/cmdline/report.py:27 msgid "" "This command creates a PDF report using reportlab that\n" " contains statistics and if selected the freeform fields." msgstr "" #: ../sdaps/cmdline/report.py:33 msgid "Create a filtered report for every checkbox." msgstr "" #: ../sdaps/cmdline/report.py:36 msgid "Short format (without freeform text fields)." msgstr "" #: ../sdaps/cmdline/report.py:41 msgid "Detailed output. (default)" msgstr "" #: ../sdaps/cmdline/report.py:47 ../sdaps/cmdline/reporttex.py:30 msgid "" "Do not include original images in the report. This is useful if there are " "privacy concerns." msgstr "" #: ../sdaps/cmdline/report.py:52 ../sdaps/cmdline/reporttex.py:35 msgid "Do not use substitutions instead of images." msgstr "" #: ../sdaps/cmdline/report.py:58 ../sdaps/cmdline/reporttex.py:46 msgid "The paper size used for the output (default: locale dependent)" msgstr "" #: ../sdaps/cmdline/report.py:61 ../sdaps/cmdline/reporttex.py:49 #, python-format msgid "Filename to store the data to (default: report_%%i.pdf)" msgstr "" #: ../sdaps/cmdline/reporttex.py:26 msgid "Create a PDF report using LaTeX." msgstr "" #: ../sdaps/cmdline/reporttex.py:27 msgid "" "This command creates a PDF report using LaTeX that\n" " contains statistics and freeform fields." msgstr "" #: ../sdaps/cmdline/reporttex.py:41 msgid "Save the generated TeX files instead of the final PDF." msgstr "" #: ../sdaps/cmdline/reset.py:26 msgid "Reset project into original state" msgstr "" #: ../sdaps/cmdline/reset.py:27 msgid "" "This command does a full reset of the project. All data\n" " will be discarded and only the empty project is left.\n" " " msgstr "" #: ../sdaps/cmdline/setup.py:27 msgid "Create a new survey using a LaTeX document." msgstr "" #: ../sdaps/cmdline/setup.py:28 msgid "" "Create a new survey from a LaTeX document. You need to\n" " be using the SDAPS class. All the metadata and options for the project\n" " can be set inside the LaTeX document." msgstr "" #: ../sdaps/cmdline/setup.py:33 msgid "The LaTeX Document" msgstr "" #: ../sdaps/cmdline/setup.py:35 msgid "" "Additional files that are required by the LaTeX document and need to be " "copied into the project directory." msgstr "" #: ../sdaps/cmdline/setup.py:39 msgid "Additional questions that are not part of the questionnaire." msgstr "" #: ../sdaps/cmdline/stamp.py:26 msgid "Add marks for automatic processing." msgstr "" #: ../sdaps/cmdline/stamp.py:27 msgid "" "This command creates the printable document. Depending on\n" " the projects setting you are required to specifiy a source for " "questionnaire\n" " IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:33 msgid "" "If using questionnaire IDs, create N questionnaires with randomized IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:36 msgid "" "If using questionnaire IDs, create questionnaires from the IDs read from the " "specified file." msgstr "" #: ../sdaps/cmdline/stamp.py:39 msgid "If using questionnaire IDs, create questionnaires for all stored IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:42 #, python-format msgid "Filename to store the data to (default: stamp_%%i.pdf)" msgstr "" #: ../sdaps/convert/__init__.py:37 #, python-format msgid "Could not apply 3D-transformation to image '%s', page %i!" msgstr "" #: ../sdaps/cover/__init__.py:40 msgid "SDAPS questionnaire" msgstr "" #: ../sdaps/csvdata/buddies.py:77 #, python-format msgid "Not importing unknown questionnaire ID \"%s\"" msgstr "" #: ../sdaps/gui/__init__.py:59 msgid "" "The survey does not have any images! Please add images (and run recognize) " "before using the GUI." msgstr "" #: ../sdaps/gui/__init__.py:211 msgid "Page|Invalid" msgstr "" #: ../sdaps/gui/__init__.py:214 #, python-format msgid "Page %i" msgid_plural "Page %i" msgstr[0] "" msgstr[1] "" #: ../sdaps/gui/__init__.py:256 msgid "Copyright © 2007-2014 The SDAPS Authors" msgstr "" #: ../sdaps/gui/__init__.py:258 msgid "Scripts for data acquisition with paper based surveys" msgstr "" #: ../sdaps/gui/__init__.py:259 msgid "http://sdaps.org" msgstr "" #: ../sdaps/gui/__init__.py:260 msgid "translator-credits" msgstr "" #: ../sdaps/gui/__init__.py:305 #, python-format msgid " of %i" msgstr "" #: ../sdaps/gui/__init__.py:306 #, python-format msgid "Recognition Quality: %.2f" msgstr "" #: ../sdaps/gui/__init__.py:322 msgid "" "You have reached the first page of the survey. Would you like to go to the " "last page?" msgstr "" #: ../sdaps/gui/__init__.py:324 msgid "Go to last page" msgstr "" #: ../sdaps/gui/__init__.py:346 msgid "" "You have reached the last page of the survey. Would you like to go to the " "first page?" msgstr "" #: ../sdaps/gui/__init__.py:348 msgid "Go to first page" msgstr "" #: ../sdaps/gui/__init__.py:457 msgid "Close without saving" msgstr "" #: ../sdaps/gui/__init__.py:461 msgid "" "Save the project before closing?\n" "\n" "If you do not save you may loose data." msgstr "" #: ../sdaps/gui/main_window.ui.h:1 msgid "Forward" msgstr "" #: ../sdaps/gui/main_window.ui.h:2 msgid "Previous" msgstr "" #: ../sdaps/gui/main_window.ui.h:3 msgid "Zoom In" msgstr "" #: ../sdaps/gui/main_window.ui.h:4 msgid "Zoom Out" msgstr "" #: ../sdaps/gui/main_window.ui.h:5 msgid "SDAPS" msgstr "" #: ../sdaps/gui/main_window.ui.h:6 msgid "_File" msgstr "" #: ../sdaps/gui/main_window.ui.h:7 msgid "_View" msgstr "" #: ../sdaps/gui/main_window.ui.h:8 msgid "_Help" msgstr "" #: ../sdaps/gui/main_window.ui.h:9 msgid "Page Rotated" msgstr "" #: ../sdaps/gui/main_window.ui.h:10 msgid "Sort by Quality" msgstr "" #: ../sdaps/gui/main_window.ui.h:11 msgid "label" msgstr "" #: ../sdaps/gui/widget_buddies.py:56 msgid "Global Properties" msgstr "" #: ../sdaps/gui/widget_buddies.py:60 msgid "Sheet valid" msgstr "" #: ../sdaps/gui/widget_buddies.py:61 msgid "Sheet Verified" msgstr "" #: ../sdaps/gui/widget_buddies.py:62 msgid "Page Verified" msgstr "" #: ../sdaps/gui/widget_buddies.py:63 msgid "Empty" msgstr "" #: ../sdaps/gui/widget_buddies.py:75 ../sdaps/gui/widget_buddies.py:105 msgid "Questionnaire ID: " msgstr "" #: ../sdaps/image/__init__.py:47 msgid "" "It appears you have not build the C extension. Please run \"./setup.py build" "\" in the toplevel directory." msgstr "" #: ../sdaps/utils/latex.py:29 msgid "" "The latex character map is missing! Please build it using the supplied tool " "(create-latexmap.py)." msgstr "" #: ../sdaps/utils/latex.py:69 msgid "" "Generated string for LaTeX contains unicode characters. This may not work " "correctly and could mean the LaTeX character map needs to be updated." msgstr "" #: ../sdaps/utils/opencv.py:35 msgid "Cannot convert PDF files as poppler is not installed or usable!" msgstr "" #: ../sdaps/utils/opencv.py:44 msgid "File does not exist" msgstr "" #. The old code used to first filter, and then run; but that is #. a bit ineffective in a way #: ../sdaps/model/survey.py:386 #, python-format msgid "%i sheet" msgid_plural "%i sheets" msgstr[0] "" msgstr[1] "" #: ../sdaps/model/survey.py:402 #, python-format msgid "Processed %i of %i sheets, took %f seconds" msgstr "" #: ../sdaps/model/survey.py:449 msgid "" "A questionnaire that is printed in duplex needs an even amount of pages!" msgstr "" #: ../sdaps/model/survey.py:453 msgid "" "The 'classic' style only supports a maximum of six pages! Use the 'code128' " "style if you require more pages." msgstr "" #: ../sdaps/model/survey.py:466 msgid "IDs need to be integers in \"classic\" style!" msgstr "" #: ../sdaps/model/survey.py:472 #, python-format msgid "Invalid character %s in questionnaire ID \"%s\" in \"code128\" style!" msgstr "" #: ../sdaps/model/survey.py:476 msgid "" "SDAPS cannot draw a questionnaire ID with the \"custom\" style. Do this " "yourself somehow!" msgstr "" #. in simplex mode every page will have a matrix; it might be a None #. matrix though #: ../sdaps/recognize/buddies.py:71 #, python-format msgid "%s, %i: Matrix not recognized." msgstr "" #: ../sdaps/recognize/buddies.py:80 #, python-format msgid "%s, %i: Rotation not found." msgstr "" #. Copy the rotation over (if required) and print warning if the rotation is unknown #: ../sdaps/recognize/buddies.py:84 #, python-format msgid "Neither %s, %i or %s, %i has a known rotation!" msgstr "" #: ../sdaps/recognize/buddies.py:96 #, python-format msgid "%s, %i: Matrix not recognized (again)." msgstr "" #: ../sdaps/recognize/buddies.py:110 #, python-format msgid "%s, %i: Could not get page number." msgstr "" #. Whoa, that should not happen. #: ../sdaps/recognize/buddies.py:130 #, python-format msgid "Neither %s, %i or %s, %i has a known page number!" msgstr "" #. We don't touch the ignore flag in this case #. Simply print a message as this should *never* happen #: ../sdaps/recognize/buddies.py:141 #, python-format msgid "" "Got a simplex document where two adjacent pages had a known page number. " "This should never happen as even simplex scans are converted to duplex by " "inserting dummy pages. Maybe you did a simplex scan but added it in duplex " "mode? The pages in question are %s, %i and %s, %i." msgstr "" #: ../sdaps/recognize/buddies.py:158 #, python-format msgid "Images %s, %i and %s, %i do not have consecutive page numbers!" msgstr "" #: ../sdaps/recognize/buddies.py:174 #, python-format msgid "No page number for page %s, %i exists." msgstr "" #: ../sdaps/recognize/buddies.py:179 #, python-format msgid "Page number for page %s, %i already used by another image." msgstr "" #: ../sdaps/recognize/buddies.py:185 #, python-format msgid "Page number %i for page %s, %i is out of range." msgstr "" #: ../sdaps/recognize/buddies.py:202 #, python-format msgid "%s, %i: Could not read survey ID, but should be able to." msgstr "" #: ../sdaps/recognize/buddies.py:206 #, python-format msgid "Could not read survey ID of either %s, %i or %s, %i!" msgstr "" #. Broken survey ID ... #: ../sdaps/recognize/buddies.py:213 #, python-format msgid "Got a wrong survey ID (%s, %i)! It is %s, but should be %i." msgstr "" #: ../sdaps/recognize/buddies.py:235 #, python-format msgid "%s, %i: Could not read questionnaire ID, but should be able to." msgstr "" #: ../sdaps/recognize/buddies.py:241 #, python-format msgid "Could not read questionnaire ID of either %s, %i or %s, %i!" msgstr "" #: ../sdaps/recognize/buddies.py:271 msgid "" "Got different IDs on different pages for at least one sheet! Do *NOT* try to " "use filters with this survey! You have to run a \"reorder\" step for this to " "work properly!" msgstr "" #: ../sdaps/recognize/buddies.py:326 msgid "No style buddy loaded. This needs to be done for the \"custom\" style!" msgstr "" #: ../sdaps/report/answers.py:188 #, python-format msgid "Answers: %i" msgstr "" #: ../sdaps/report/answers.py:190 #, python-format msgid "Mean: %.2f" msgstr "" #: ../sdaps/report/answers.py:192 #, python-format msgid "Standard Deviation: %.2f" msgstr "" #: ../sdaps/report/__init__.py:75 ../sdaps/reporttex/__init__.py:140 msgid "Turned in Questionnaires" msgstr "" #: ../sdaps/report/__init__.py:92 ../sdaps/reporttex/__init__.py:139 msgid "sdaps report" msgstr "" #: ../sdaps/reset/__init__.py:29 msgid "Removing stored data..." msgstr "" #: ../sdaps/setup/buddies.py:62 #, python-format msgid "Head %(l0)i got no title." msgstr "" #: ../sdaps/setup/buddies.py:74 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no question." msgstr "" #: ../sdaps/setup/buddies.py:114 #, python-format msgid "Error in question \"%s\"" msgstr "" #: ../sdaps/setup/buddies.py:118 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no boxes." msgstr "" #: ../sdaps/setup/buddies.py:167 #, python-format msgid "%(class)s %(l0)i.%(l1)i lower box out of range." msgstr "" #: ../sdaps/setup/buddies.py:172 #, python-format msgid "%(class)s %(l0)i.%(l1)i upper box out of range." msgstr "" #: ../sdaps/setup/buddies.py:177 #, python-format msgid "%(class)s %(l0)i.%(l1)i lower box not before upper box." msgstr "" #: ../sdaps/setup/buddies.py:213 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly two answers." msgstr "" #: ../sdaps/setup/buddies.py:234 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly one box." msgstr "" #: ../sdaps/stamp/__init__.py:38 msgid "" "You may not specify the number of sheets for this survey. All questionnaires " "will be identical as the survey has been configured to not use questionnaire " "IDs for each sheet." msgstr "" #: ../sdaps/stamp/__init__.py:76 msgid "" "This survey has been configured to use questionnaire IDs. Each questionnaire " "will be unique. You need to use on of the options to add new IDs or use the " "existing ones." msgstr "" #: ../sdaps/stamp/latex.py:18 msgid "" "There should be no need to stamp a SDAPS Project that uses LaTeX and does " "not have different questionnaire IDs printed on each sheet.\n" "I am going to do so anyways." msgstr "" #: ../sdaps/stamp/latex.py:26 #, python-format msgid "Running %s now twice to generate the stamped questionnaire." msgstr "" #: ../sdaps/stamp/latex.py:30 ../sdaps/setuptex/__init__.py:107 #: ../sdaps/setuptex/__init__.py:148 ../sdaps/reporttex/__init__.py:162 #, python-format msgid "Error running \"%s\" to compile the LaTeX file." msgstr "" #: ../sdaps/stamp/latex.py:36 #, python-format msgid "" "An error occured during creation of the report. Temporary files left in '%s'." msgstr "" #: ../sdaps/setuptex/__init__.py:46 msgid "The survey directory already exists." msgstr "" #: ../sdaps/setuptex/__init__.py:51 #, python-format msgid "Unknown file type (%s). questionnaire_tex should be of type text/x-tex." msgstr "" #: ../sdaps/setuptex/__init__.py:52 msgid "Will keep going, but expect failure!" msgstr "" #: ../sdaps/setuptex/__init__.py:57 #, python-format msgid "Unknown file type (%s). additionalqobjects should be text/plain." msgstr "" #: ../sdaps/setuptex/__init__.py:103 ../sdaps/setuptex/__init__.py:143 #, python-format msgid "Running %s now twice to generate the questionnaire." msgstr "" #: ../sdaps/setuptex/__init__.py:122 msgid "Caught an Exception while parsing the SDAPS file. The current state is:" msgstr "" #: ../sdaps/setuptex/__init__.py:136 msgid "" "Some combination of options and project properties do not work. Aborted " "Setup." msgstr "" #: ../sdaps/setuptex/__init__.py:162 msgid "" "An error occured in the setup routine. The survey directory still exists. " "You can for example check the questionnaire.log file for LaTeX compile " "errors." msgstr "" #: ../sdaps/reporttex/__init__.py:107 msgid "author|Unknown" msgstr "" #: ../sdaps/reporttex/__init__.py:138 msgid "tex language|english" msgstr "" #: ../sdaps/reporttex/__init__.py:155 #, python-format msgid "The TeX project with the report data is located at '%s'." msgstr "" #: ../sdaps/reporttex/__init__.py:158 #, python-format msgid "Running %s now twice to generate the report." msgstr "" #: ../sdaps/reporttex/__init__.py:168 #, python-format msgid "An occured during creation of the report. Temporary files left in '%s'." msgstr "" sdaps-1.9.8/po/ko.po0000644000175000000660000006273613410742274015010 0ustar benjaminlock00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:10+0100\n" "PO-Revision-Date: 2018-12-26 14:09+0000\n" "Last-Translator: Hyunmin Kim (Brandon) \n" "Language-Team: Korean " "\n" "Language: ko\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Weblate 3.4-dev\n" #: ../sdaps/script.py:41 msgid "SDAPS -- Paper based survey tool." msgstr "" #: ../sdaps/script.py:45 msgid "command list|Commands:" msgstr "명령어 항목|명령어들:" #: ../sdaps/script.py:50 msgid "project directory|The SDAPS project." msgstr "프로젝트 경로|새로운 프로젝트." #: ../sdaps/add/__init__.py:55 #, python-format msgid "" "Invalid input file %s. You need to specify a (multipage) monochrome TIFF as " "input." msgstr "%s 는 유효하지 않은 입력 파일입니다. 입력 파일로써 monochrome TIFF 형식만 가능합니다." #: ../sdaps/add/__init__.py:67 #, python-format msgid "" "Not adding %s because it has a wrong page count (needs to be a mulitple of " "%i)." msgstr "" #: ../sdaps/boxgallery/__init__.py:108 #, python-format msgid "Rendering boxgallery for metric \"%s\"." msgstr "" #: ../sdaps/log.py:37 msgid "Warning: " msgstr "경고: " #: ../sdaps/log.py:41 msgid "Error: " msgstr "오류: " #: ../sdaps/cmdline/add.py:31 msgid "Add scanned questionnaires to the survey." msgstr "설문 조사를 위해 스캔된 설문 항목을 추가해주세요." #: ../sdaps/cmdline/add.py:32 msgid "" "This command is used to add scanned images to the survey.\n" " The image data needs to be a (multipage) 300dpi monochrome TIFF file. " "You\n" " may choose not to copy the data into the project directory. In that " "case\n" " the data will be referenced using a relative path." msgstr "" #: ../sdaps/cmdline/add.py:38 msgid "Convert given files and add the result." msgstr "입력 파일들을 변환하고 그 결과를 추가합니다." #: ../sdaps/cmdline/add.py:43 msgid "" "Do a 3D-transformation after finding the corner marks. If the\n" " corner marks are not found then the image will be added as-is." msgstr "" "모서리 표시 위치를 찾은 뒤 3D-변환을 거칩니다. 만일에 그\n" "모서리 표시가 발견되지 않으면 이미지가 as-is로 추가될 것입니다." #: ../sdaps/cmdline/add.py:49 msgid "" "Force adding the images even if the page count is wrong (only use if you " "know what you are doing)." msgstr "" #: ../sdaps/cmdline/add.py:53 msgid "Copy the files into the directory (default)." msgstr "경로에 파일들을 복사합니다 (기본값)." #: ../sdaps/cmdline/add.py:58 msgid "Do not copy the files into the directory." msgstr "경로에 파일들을 복사하지 마세요." #: ../sdaps/cmdline/add.py:62 msgid "" "Images contain a duplex scan of a simplex questionnaire (default: simplex " "scan)." msgstr "간단한 설문조사의 duplex 스캔을 포함하는 이미지들 (기본값: simplex 스캔)." #: ../sdaps/cmdline/add.py:68 ../sdaps/cmdline/convert.py:48 msgid "A number of TIFF image files." msgstr "수많은 TIFF 이미지 파일들." #: ../sdaps/cmdline/add.py:94 msgid "The --no-copy option is not compatible with --convert!" msgstr "" #: ../sdaps/cmdline/add.py:103 msgid "Converting input files into a single temporary file." msgstr "" #: ../sdaps/cmdline/add.py:115 msgid "" "The page count of the created temporary file does not work with this survey." msgstr "" #: ../sdaps/cmdline/add.py:120 msgid "Running the conversion failed." msgstr "변환 작업이 실패했습니다." #: ../sdaps/cmdline/add.py:126 #, python-format msgid "Processing %s" msgstr "진행중 %s" #: ../sdaps/cmdline/add.py:130 ../sdaps/reset/__init__.py:33 msgid "Done" msgstr "완료" #: ../sdaps/cmdline/annotate.py:28 msgid "Annotate the questionnaire and show the recognized positions." msgstr "" #: ../sdaps/cmdline/annotate.py:29 msgid "" "This command is mainly a debug utility. It creates an\n" " annotated version of the questionnaire, with the information that SDAPS\n" " knows about it overlayed on top." msgstr "" #: ../sdaps/cmdline/boxgallery.py:31 msgid "Create PDFs with boxes sorted by the detection heuristics." msgstr "" #: ../sdaps/cmdline/boxgallery.py:32 msgid "" "SDAPS uses multiple heuristics to detect determine the\n" " state of checkboxes. There is a list for each heuristic giving the " "expected\n" " state and the quality of the value (see defs.py). Using this command a " "PDF\n" " will be created for each of the heuristics so that one can adjust the\n" " values." msgstr "" #: ../sdaps/cmdline/boxgallery.py:40 msgid "" "Reruns part of the recognition process and retrieves debug images from this " "step." msgstr "" #: ../sdaps/cmdline/convert.py:30 msgid "Convert a set of images to the correct image format." msgstr "이미지 집합을 알맞는 이미지 형식으로 변환합니다." #: ../sdaps/cmdline/convert.py:31 msgid "" "This command can be used if you scanned files in something\n" " other than the expected monochrome TIFF mode. All given files will\n" " be loaded, converted to monochrome and stored in a multipage 1bpp\n" " TIFF file. Optionally, you can select \"3D transformation\"\\ ,which " "may facilitate\n" " working with photos of questionnaires instead of scans." msgstr "" #: ../sdaps/cmdline/convert.py:38 msgid "" "Do a 3D-transformation after finding the corner marks.\n" " If they are not found, the image will be processed as-is." msgstr "" #: ../sdaps/cmdline/convert.py:44 msgid "The location of the output file." msgstr "결과 파일의 위치." #: ../sdaps/cmdline/convert.py:57 msgid "No output filename specified!" msgstr "결과 파일명이 지정되지 않았습니다!" #: ../sdaps/cmdline/cover.py:27 msgid "Create a cover for the questionnaires." msgstr "설문조사에 대한 커버를 만드세요." #: ../sdaps/cmdline/cover.py:28 msgid "" "This command creates a cover page for questionnaires. All\n" " the metadata of the survey will be printed on the page." msgstr "" #: ../sdaps/cmdline/cover.py:31 #, python-format msgid "Filename to store the data to (default: cover_%%i.pdf)" msgstr "" #: ../sdaps/cmdline/csvdata.py:34 msgid "Import or export data to/from CSV files." msgstr "" #: ../sdaps/cmdline/csvdata.py:35 msgid "" "Import or export data to/from a CSV file. The first line\n" " is a header which defines questionnaire_id and global_id, and a column\n" " for each checkbox and textfield. Note that the import is currently very\n" " limited, as you need to specifiy the questionnaire ID to select the " "sheet\n" " which should be updated." msgstr "" #: ../sdaps/cmdline/csvdata.py:44 msgid "Export data to CSV file." msgstr "CSV 파일로 데이터를 출력합니다." #: ../sdaps/cmdline/csvdata.py:46 #, python-format msgid "Filename to store the data to (default: data_%%i.csv)" msgstr "" #: ../sdaps/cmdline/csvdata.py:48 msgid "The delimiter used in the CSV file (default ',')" msgstr "" #: ../sdaps/cmdline/csvdata.py:52 ../sdaps/cmdline/report.py:31 #: ../sdaps/cmdline/reporttex.py:52 msgid "Filter to only export a partial dataset." msgstr "" #: ../sdaps/cmdline/csvdata.py:54 msgid "Export images of freeform fields." msgstr "" #: ../sdaps/cmdline/csvdata.py:60 msgid "Export an image for each question that includes all boxes." msgstr "" #: ../sdaps/cmdline/csvdata.py:66 msgid "Export the recognition quality for each checkbox." msgstr "" #: ../sdaps/cmdline/csvdata.py:74 msgid "Import data to from a CSV file." msgstr "" #: ../sdaps/cmdline/csvdata.py:76 msgid "The file to import." msgstr "" #: ../sdaps/cmdline/gui.py:28 msgid "Launch a GUI. You can view and alter the (recognized) answers with it." msgstr "" #: ../sdaps/cmdline/gui.py:29 msgid "" "This command launches a graphical user interface that can\n" " be used to correct answers. You need to run \"recognize\" before using " "it.\n" " " msgstr "" #: ../sdaps/cmdline/gui.py:34 msgid "Filter to only show a partial dataset." msgstr "" #: ../sdaps/cmdline/ids.py:29 msgid "Export and import questionnaire IDs." msgstr "" #: ../sdaps/cmdline/ids.py:30 msgid "" "This command can be used to import and export questionnaire\n" " IDs. It only makes sense in projects where such an ID is printed on the\n" " questionnaire. Note that you can also add IDs by using the stamp " "command,\n" " which will give you the PDF at the same time." msgstr "" #: ../sdaps/cmdline/ids.py:35 #, python-format msgid "Filename to store the data to (default: ids_%%i)" msgstr "" #: ../sdaps/cmdline/ids.py:38 msgid "Add IDs to the internal list from the specified file." msgstr "" #: ../sdaps/cmdline/info.py:28 msgid "Display and modify metadata of project." msgstr "" #: ../sdaps/cmdline/info.py:29 msgid "" "This command lets you modify the metadata of the SDAPS\n" " project. You can modify, add and remove arbitrary keys that will be " "printed\n" " on the report. The only key that always exist is \"title\".\n" " If no key is given then a list of defined keys is printed." msgstr "" #: ../sdaps/cmdline/info.py:36 msgid "Delete the key and value pair." msgstr "" #: ../sdaps/cmdline/info.py:40 msgid "The key to display or modify." msgstr "" #: ../sdaps/cmdline/info.py:44 msgid "Set the given key to this value." msgstr "" #: ../sdaps/cmdline/info.py:69 msgid "Existing fields:\n" msgstr "" #: ../sdaps/cmdline/recognize.py:28 msgid "Run the optical mark recognition." msgstr "" #: ../sdaps/cmdline/recognize.py:29 msgid "" "Iterates over all images and runs the optical mark\n" " recognition. It will reevaluate sheets even if \"recognize\" has " "already\n" " run or manual changes were made." msgstr "" #: ../sdaps/cmdline/recognize.py:34 msgid "" "Only identify the page properties, but don't recognize the checkbox states." msgstr "" #: ../sdaps/cmdline/recognize.py:39 msgid "" "Rerun the recognition for all pages. The default is to skip all pages that " "were recognized or verified already." msgstr "" #: ../sdaps/cmdline/reorder.py:26 msgid "Reorder pages according to questionnaire ID." msgstr "" #: ../sdaps/cmdline/reorder.py:27 msgid "" "This command reorders all pages according to the already\n" " recognized questionnaire ID. To use it add all the files to the " "project,\n" " then run a partial recognition using \"recognize --identify\". After " "this\n" " you have to run this command to reorder the data for the real " "recognition.\n" " " msgstr "" #: ../sdaps/cmdline/report.py:26 msgid "Create a PDF report." msgstr "" #: ../sdaps/cmdline/report.py:27 msgid "" "This command creates a PDF report using reportlab that\n" " contains statistics and if selected the freeform fields." msgstr "" #: ../sdaps/cmdline/report.py:33 msgid "Create a filtered report for every checkbox." msgstr "" #: ../sdaps/cmdline/report.py:36 msgid "Short format (without freeform text fields)." msgstr "" #: ../sdaps/cmdline/report.py:41 msgid "Detailed output. (default)" msgstr "" #: ../sdaps/cmdline/report.py:47 ../sdaps/cmdline/reporttex.py:30 msgid "" "Do not include original images in the report. This is useful if there are " "privacy concerns." msgstr "" #: ../sdaps/cmdline/report.py:52 ../sdaps/cmdline/reporttex.py:35 msgid "Do not use substitutions instead of images." msgstr "" #: ../sdaps/cmdline/report.py:58 ../sdaps/cmdline/reporttex.py:46 msgid "The paper size used for the output (default: locale dependent)" msgstr "" #: ../sdaps/cmdline/report.py:61 ../sdaps/cmdline/reporttex.py:49 #, python-format msgid "Filename to store the data to (default: report_%%i.pdf)" msgstr "" #: ../sdaps/cmdline/reporttex.py:26 msgid "Create a PDF report using LaTeX." msgstr "" #: ../sdaps/cmdline/reporttex.py:27 msgid "" "This command creates a PDF report using LaTeX that\n" " contains statistics and freeform fields." msgstr "" #: ../sdaps/cmdline/reporttex.py:41 msgid "Save the generated TeX files instead of the final PDF." msgstr "" #: ../sdaps/cmdline/reset.py:26 msgid "Reset project into original state" msgstr "" #: ../sdaps/cmdline/reset.py:27 msgid "" "This command does a full reset of the project. All data\n" " will be discarded and only the empty project is left.\n" " " msgstr "" #: ../sdaps/cmdline/setup.py:27 msgid "Create a new survey using a LaTeX document." msgstr "" #: ../sdaps/cmdline/setup.py:28 msgid "" "Create a new survey from a LaTeX document. You need to\n" " be using the SDAPS class. All the metadata and options for the project\n" " can be set inside the LaTeX document." msgstr "" #: ../sdaps/cmdline/setup.py:33 msgid "The LaTeX Document" msgstr "" #: ../sdaps/cmdline/setup.py:35 msgid "" "Additional files that are required by the LaTeX document and need to be " "copied into the project directory." msgstr "" #: ../sdaps/cmdline/setup.py:39 msgid "Additional questions that are not part of the questionnaire." msgstr "" #: ../sdaps/cmdline/stamp.py:26 msgid "Add marks for automatic processing." msgstr "" #: ../sdaps/cmdline/stamp.py:27 msgid "" "This command creates the printable document. Depending on\n" " the projects setting you are required to specifiy a source for " "questionnaire\n" " IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:33 msgid "" "If using questionnaire IDs, create N questionnaires with randomized IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:36 msgid "" "If using questionnaire IDs, create questionnaires from the IDs read from the " "specified file." msgstr "" #: ../sdaps/cmdline/stamp.py:39 msgid "If using questionnaire IDs, create questionnaires for all stored IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:42 #, python-format msgid "Filename to store the data to (default: stamp_%%i.pdf)" msgstr "" #: ../sdaps/convert/__init__.py:37 #, python-format msgid "Could not apply 3D-transformation to image '%s', page %i!" msgstr "" #: ../sdaps/cover/__init__.py:40 msgid "SDAPS questionnaire" msgstr "" #: ../sdaps/csvdata/buddies.py:77 #, python-format msgid "Not importing unknown questionnaire ID \"%s\"" msgstr "" #: ../sdaps/gui/__init__.py:59 msgid "" "The survey does not have any images! Please add images (and run recognize) " "before using the GUI." msgstr "" #: ../sdaps/gui/__init__.py:211 msgid "Page|Invalid" msgstr "" #: ../sdaps/gui/__init__.py:214 #, python-format msgid "Page %i" msgid_plural "Page %i" msgstr[0] "" msgstr[1] "" #: ../sdaps/gui/__init__.py:256 msgid "Copyright © 2007-2014 The SDAPS Authors" msgstr "" #: ../sdaps/gui/__init__.py:258 msgid "Scripts for data acquisition with paper based surveys" msgstr "" #: ../sdaps/gui/__init__.py:259 msgid "http://sdaps.org" msgstr "" #: ../sdaps/gui/__init__.py:260 msgid "translator-credits" msgstr "" #: ../sdaps/gui/__init__.py:305 #, python-format msgid " of %i" msgstr "" #: ../sdaps/gui/__init__.py:306 #, python-format msgid "Recognition Quality: %.2f" msgstr "" #: ../sdaps/gui/__init__.py:322 msgid "" "You have reached the first page of the survey. Would you like to go to the " "last page?" msgstr "" #: ../sdaps/gui/__init__.py:324 msgid "Go to last page" msgstr "" #: ../sdaps/gui/__init__.py:346 msgid "" "You have reached the last page of the survey. Would you like to go to the " "first page?" msgstr "" #: ../sdaps/gui/__init__.py:348 msgid "Go to first page" msgstr "" #: ../sdaps/gui/__init__.py:457 msgid "Close without saving" msgstr "" #: ../sdaps/gui/__init__.py:461 msgid "" "Save the project before closing?\n" "\n" "If you do not save you may loose data." msgstr "" #: ../sdaps/gui/main_window.ui.h:1 msgid "Forward" msgstr "" #: ../sdaps/gui/main_window.ui.h:2 msgid "Previous" msgstr "" #: ../sdaps/gui/main_window.ui.h:3 msgid "Zoom In" msgstr "" #: ../sdaps/gui/main_window.ui.h:4 msgid "Zoom Out" msgstr "" #: ../sdaps/gui/main_window.ui.h:5 msgid "SDAPS" msgstr "" #: ../sdaps/gui/main_window.ui.h:6 msgid "_File" msgstr "" #: ../sdaps/gui/main_window.ui.h:7 msgid "_View" msgstr "" #: ../sdaps/gui/main_window.ui.h:8 msgid "_Help" msgstr "" #: ../sdaps/gui/main_window.ui.h:9 msgid "Page Rotated" msgstr "" #: ../sdaps/gui/main_window.ui.h:10 msgid "Sort by Quality" msgstr "" #: ../sdaps/gui/main_window.ui.h:11 msgid "label" msgstr "" #: ../sdaps/gui/widget_buddies.py:56 msgid "Global Properties" msgstr "" #: ../sdaps/gui/widget_buddies.py:60 msgid "Sheet valid" msgstr "" #: ../sdaps/gui/widget_buddies.py:61 msgid "Sheet Verified" msgstr "" #: ../sdaps/gui/widget_buddies.py:62 msgid "Page Verified" msgstr "" #: ../sdaps/gui/widget_buddies.py:63 msgid "Empty" msgstr "" #: ../sdaps/gui/widget_buddies.py:75 ../sdaps/gui/widget_buddies.py:105 msgid "Questionnaire ID: " msgstr "" #: ../sdaps/image/__init__.py:47 msgid "" "It appears you have not build the C extension. Please run \"./setup.py build" "\" in the toplevel directory." msgstr "" #: ../sdaps/utils/latex.py:29 msgid "" "The latex character map is missing! Please build it using the supplied tool " "(create-latexmap.py)." msgstr "" #: ../sdaps/utils/latex.py:69 msgid "" "Generated string for LaTeX contains unicode characters. This may not work " "correctly and could mean the LaTeX character map needs to be updated." msgstr "" #: ../sdaps/utils/opencv.py:35 msgid "Cannot convert PDF files as poppler is not installed or usable!" msgstr "" #: ../sdaps/utils/opencv.py:44 msgid "File does not exist" msgstr "" #. The old code used to first filter, and then run; but that is #. a bit ineffective in a way #: ../sdaps/model/survey.py:386 #, python-format msgid "%i sheet" msgid_plural "%i sheets" msgstr[0] "" msgstr[1] "" #: ../sdaps/model/survey.py:402 #, python-format msgid "Processed %i of %i sheets, took %f seconds" msgstr "" #: ../sdaps/model/survey.py:449 msgid "" "A questionnaire that is printed in duplex needs an even amount of pages!" msgstr "" #: ../sdaps/model/survey.py:453 msgid "" "The 'classic' style only supports a maximum of six pages! Use the 'code128' " "style if you require more pages." msgstr "" #: ../sdaps/model/survey.py:466 msgid "IDs need to be integers in \"classic\" style!" msgstr "" #: ../sdaps/model/survey.py:472 #, python-format msgid "Invalid character %s in questionnaire ID \"%s\" in \"code128\" style!" msgstr "" #: ../sdaps/model/survey.py:476 msgid "" "SDAPS cannot draw a questionnaire ID with the \"custom\" style. Do this " "yourself somehow!" msgstr "" #. in simplex mode every page will have a matrix; it might be a None #. matrix though #: ../sdaps/recognize/buddies.py:71 #, python-format msgid "%s, %i: Matrix not recognized." msgstr "" #: ../sdaps/recognize/buddies.py:80 #, python-format msgid "%s, %i: Rotation not found." msgstr "" #. Copy the rotation over (if required) and print warning if the rotation is unknown #: ../sdaps/recognize/buddies.py:84 #, python-format msgid "Neither %s, %i or %s, %i has a known rotation!" msgstr "" #: ../sdaps/recognize/buddies.py:96 #, python-format msgid "%s, %i: Matrix not recognized (again)." msgstr "" #: ../sdaps/recognize/buddies.py:110 #, python-format msgid "%s, %i: Could not get page number." msgstr "" #. Whoa, that should not happen. #: ../sdaps/recognize/buddies.py:130 #, python-format msgid "Neither %s, %i or %s, %i has a known page number!" msgstr "" #. We don't touch the ignore flag in this case #. Simply print a message as this should *never* happen #: ../sdaps/recognize/buddies.py:141 #, python-format msgid "" "Got a simplex document where two adjacent pages had a known page number. " "This should never happen as even simplex scans are converted to duplex by " "inserting dummy pages. Maybe you did a simplex scan but added it in duplex " "mode? The pages in question are %s, %i and %s, %i." msgstr "" #: ../sdaps/recognize/buddies.py:158 #, python-format msgid "Images %s, %i and %s, %i do not have consecutive page numbers!" msgstr "" #: ../sdaps/recognize/buddies.py:174 #, python-format msgid "No page number for page %s, %i exists." msgstr "" #: ../sdaps/recognize/buddies.py:179 #, python-format msgid "Page number for page %s, %i already used by another image." msgstr "" #: ../sdaps/recognize/buddies.py:185 #, python-format msgid "Page number %i for page %s, %i is out of range." msgstr "" #: ../sdaps/recognize/buddies.py:202 #, python-format msgid "%s, %i: Could not read survey ID, but should be able to." msgstr "" #: ../sdaps/recognize/buddies.py:206 #, python-format msgid "Could not read survey ID of either %s, %i or %s, %i!" msgstr "" #. Broken survey ID ... #: ../sdaps/recognize/buddies.py:213 #, python-format msgid "Got a wrong survey ID (%s, %i)! It is %s, but should be %i." msgstr "" #: ../sdaps/recognize/buddies.py:235 #, python-format msgid "%s, %i: Could not read questionnaire ID, but should be able to." msgstr "" #: ../sdaps/recognize/buddies.py:241 #, python-format msgid "Could not read questionnaire ID of either %s, %i or %s, %i!" msgstr "" #: ../sdaps/recognize/buddies.py:271 msgid "" "Got different IDs on different pages for at least one sheet! Do *NOT* try to " "use filters with this survey! You have to run a \"reorder\" step for this to " "work properly!" msgstr "" #: ../sdaps/recognize/buddies.py:326 msgid "No style buddy loaded. This needs to be done for the \"custom\" style!" msgstr "" #: ../sdaps/report/answers.py:188 #, python-format msgid "Answers: %i" msgstr "" #: ../sdaps/report/answers.py:190 #, python-format msgid "Mean: %.2f" msgstr "" #: ../sdaps/report/answers.py:192 #, python-format msgid "Standard Deviation: %.2f" msgstr "" #: ../sdaps/report/__init__.py:75 ../sdaps/reporttex/__init__.py:140 msgid "Turned in Questionnaires" msgstr "" #: ../sdaps/report/__init__.py:92 ../sdaps/reporttex/__init__.py:139 msgid "sdaps report" msgstr "" #: ../sdaps/reset/__init__.py:29 msgid "Removing stored data..." msgstr "" #: ../sdaps/setup/buddies.py:62 #, python-format msgid "Head %(l0)i got no title." msgstr "" #: ../sdaps/setup/buddies.py:74 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no question." msgstr "" #: ../sdaps/setup/buddies.py:114 #, python-format msgid "Error in question \"%s\"" msgstr "" #: ../sdaps/setup/buddies.py:118 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no boxes." msgstr "" #: ../sdaps/setup/buddies.py:167 #, python-format msgid "%(class)s %(l0)i.%(l1)i lower box out of range." msgstr "" #: ../sdaps/setup/buddies.py:172 #, python-format msgid "%(class)s %(l0)i.%(l1)i upper box out of range." msgstr "" #: ../sdaps/setup/buddies.py:177 #, python-format msgid "%(class)s %(l0)i.%(l1)i lower box not before upper box." msgstr "" #: ../sdaps/setup/buddies.py:213 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly two answers." msgstr "" #: ../sdaps/setup/buddies.py:234 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly one box." msgstr "" #: ../sdaps/stamp/__init__.py:38 msgid "" "You may not specify the number of sheets for this survey. All questionnaires " "will be identical as the survey has been configured to not use questionnaire " "IDs for each sheet." msgstr "" #: ../sdaps/stamp/__init__.py:76 msgid "" "This survey has been configured to use questionnaire IDs. Each questionnaire " "will be unique. You need to use on of the options to add new IDs or use the " "existing ones." msgstr "" #: ../sdaps/stamp/latex.py:18 msgid "" "There should be no need to stamp a SDAPS Project that uses LaTeX and does " "not have different questionnaire IDs printed on each sheet.\n" "I am going to do so anyways." msgstr "" #: ../sdaps/stamp/latex.py:26 #, python-format msgid "Running %s now twice to generate the stamped questionnaire." msgstr "" #: ../sdaps/stamp/latex.py:30 ../sdaps/setuptex/__init__.py:107 #: ../sdaps/setuptex/__init__.py:148 ../sdaps/reporttex/__init__.py:162 #, python-format msgid "Error running \"%s\" to compile the LaTeX file." msgstr "" #: ../sdaps/stamp/latex.py:36 #, python-format msgid "" "An error occured during creation of the report. Temporary files left in '%s'." msgstr "" #: ../sdaps/setuptex/__init__.py:46 msgid "The survey directory already exists." msgstr "" #: ../sdaps/setuptex/__init__.py:51 #, python-format msgid "Unknown file type (%s). questionnaire_tex should be of type text/x-tex." msgstr "" #: ../sdaps/setuptex/__init__.py:52 msgid "Will keep going, but expect failure!" msgstr "" #: ../sdaps/setuptex/__init__.py:57 #, python-format msgid "Unknown file type (%s). additionalqobjects should be text/plain." msgstr "" #: ../sdaps/setuptex/__init__.py:103 ../sdaps/setuptex/__init__.py:143 #, python-format msgid "Running %s now twice to generate the questionnaire." msgstr "" #: ../sdaps/setuptex/__init__.py:122 msgid "Caught an Exception while parsing the SDAPS file. The current state is:" msgstr "" #: ../sdaps/setuptex/__init__.py:136 msgid "" "Some combination of options and project properties do not work. Aborted " "Setup." msgstr "" #: ../sdaps/setuptex/__init__.py:162 msgid "" "An error occured in the setup routine. The survey directory still exists. " "You can for example check the questionnaire.log file for LaTeX compile " "errors." msgstr "" #: ../sdaps/reporttex/__init__.py:107 msgid "author|Unknown" msgstr "" #: ../sdaps/reporttex/__init__.py:138 msgid "tex language|english" msgstr "" #: ../sdaps/reporttex/__init__.py:155 #, python-format msgid "The TeX project with the report data is located at '%s'." msgstr "" #: ../sdaps/reporttex/__init__.py:158 #, python-format msgid "Running %s now twice to generate the report." msgstr "" #: ../sdaps/reporttex/__init__.py:168 #, python-format msgid "An occured during creation of the report. Temporary files left in '%s'." msgstr "" sdaps-1.9.8/po/nb.po0000644000175000000660000006752113423051645014772 0ustar benjaminlock00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:10+0100\n" "PO-Revision-Date: 2019-01-24 22:05+0000\n" "Last-Translator: Allan Nordhøy \n" "Language-Team: Norwegian Bokmål \n" "Language: nb\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 3.4\n" #: ../sdaps/script.py:41 msgid "SDAPS -- Paper based survey tool." msgstr "SDAPS -- Papirbasert spørreundersøkelsesverktøy." #: ../sdaps/script.py:45 msgid "command list|Commands:" msgstr "kommandoliste|Kommandoer:" #: ../sdaps/script.py:50 msgid "project directory|The SDAPS project." msgstr "prosjektmappe|SDAPS-prosjektet." #: ../sdaps/add/__init__.py:55 #, python-format msgid "" "Invalid input file %s. You need to specify a (multipage) monochrome TIFF as " "input." msgstr "" "Ugyldig inndatafil %s. Du må angi en (flersidig) ensfarget TIFF som inndata." #: ../sdaps/add/__init__.py:67 #, python-format msgid "" "Not adding %s because it has a wrong page count (needs to be a mulitple of " "%i)." msgstr "" "Legger ikke til %s fordi det har galt sideantall (må være multippel av %i)." #: ../sdaps/boxgallery/__init__.py:108 #, python-format msgid "Rendering boxgallery for metric \"%s\"." msgstr "" #: ../sdaps/log.py:37 msgid "Warning: " msgstr "Advarsel: " #: ../sdaps/log.py:41 msgid "Error: " msgstr "Feil: " #: ../sdaps/cmdline/add.py:31 msgid "Add scanned questionnaires to the survey." msgstr "Legg til skannede spørreskjema til i spørreundersøkelsen." #: ../sdaps/cmdline/add.py:32 msgid "" "This command is used to add scanned images to the survey.\n" " The image data needs to be a (multipage) 300dpi monochrome TIFF file. " "You\n" " may choose not to copy the data into the project directory. In that " "case\n" " the data will be referenced using a relative path." msgstr "" #: ../sdaps/cmdline/add.py:38 msgid "Convert given files and add the result." msgstr "Konverter gitte filer og legg til resultatet." #: ../sdaps/cmdline/add.py:43 msgid "" "Do a 3D-transformation after finding the corner marks. If the\n" " corner marks are not found then the image will be added as-is." msgstr "" #: ../sdaps/cmdline/add.py:49 msgid "" "Force adding the images even if the page count is wrong (only use if you " "know what you are doing)." msgstr "" #: ../sdaps/cmdline/add.py:53 msgid "Copy the files into the directory (default)." msgstr "Kopier filene inn i mappa (forvalg)." #: ../sdaps/cmdline/add.py:58 msgid "Do not copy the files into the directory." msgstr "Ikke kopier filene inn i mappa." #: ../sdaps/cmdline/add.py:62 msgid "" "Images contain a duplex scan of a simplex questionnaire (default: simplex " "scan)." msgstr "" #: ../sdaps/cmdline/add.py:68 ../sdaps/cmdline/convert.py:48 msgid "A number of TIFF image files." msgstr "Et antall TIFF-bildefiler." #: ../sdaps/cmdline/add.py:94 msgid "The --no-copy option is not compatible with --convert!" msgstr "--no-copy -valget er ikke kompatibelt med --convert." #: ../sdaps/cmdline/add.py:103 msgid "Converting input files into a single temporary file." msgstr "Koverterer inndatafiler til én midlertidig fil." #: ../sdaps/cmdline/add.py:115 msgid "" "The page count of the created temporary file does not work with this survey." msgstr "" "Sideantallet av opprettet midlertidig fil fungerer ikke med denne " "spørreundersøkelsen." #: ../sdaps/cmdline/add.py:120 #, fuzzy msgid "Running the conversion failed." msgstr "Konvertering mislyktes." #: ../sdaps/cmdline/add.py:126 #, python-format msgid "Processing %s" msgstr "Behandler %s" #: ../sdaps/cmdline/add.py:130 ../sdaps/reset/__init__.py:33 msgid "Done" msgstr "Ferdig" #: ../sdaps/cmdline/annotate.py:28 msgid "Annotate the questionnaire and show the recognized positions." msgstr "" #: ../sdaps/cmdline/annotate.py:29 msgid "" "This command is mainly a debug utility. It creates an\n" " annotated version of the questionnaire, with the information that SDAPS\n" " knows about it overlayed on top." msgstr "" #: ../sdaps/cmdline/boxgallery.py:31 msgid "Create PDFs with boxes sorted by the detection heuristics." msgstr "" #: ../sdaps/cmdline/boxgallery.py:32 msgid "" "SDAPS uses multiple heuristics to detect determine the\n" " state of checkboxes. There is a list for each heuristic giving the " "expected\n" " state and the quality of the value (see defs.py). Using this command a " "PDF\n" " will be created for each of the heuristics so that one can adjust the\n" " values." msgstr "" #: ../sdaps/cmdline/boxgallery.py:40 msgid "" "Reruns part of the recognition process and retrieves debug images from this " "step." msgstr "" "Kjører deler av gjenkjennelsesprosessen igjen, og henter inn " "feilrettingsbilder fra dette steget." #: ../sdaps/cmdline/convert.py:30 msgid "Convert a set of images to the correct image format." msgstr "" #: ../sdaps/cmdline/convert.py:31 msgid "" "This command can be used if you scanned files in something\n" " other than the expected monochrome TIFF mode. All given files will\n" " be loaded, converted to monochrome and stored in a multipage 1bpp\n" " TIFF file. Optionally, you can select \"3D transformation\"\\ ,which " "may facilitate\n" " working with photos of questionnaires instead of scans." msgstr "" #: ../sdaps/cmdline/convert.py:38 msgid "" "Do a 3D-transformation after finding the corner marks.\n" " If they are not found, the image will be processed as-is." msgstr "" #: ../sdaps/cmdline/convert.py:44 #, fuzzy msgid "The location of the output file." msgstr "Plassering for utdata-fil. Må angis." #: ../sdaps/cmdline/convert.py:57 msgid "No output filename specified!" msgstr "Inget utdata-filnavn angitt!" #: ../sdaps/cmdline/cover.py:27 msgid "Create a cover for the questionnaires." msgstr "Opprett omslag for spørreskjemaene." #: ../sdaps/cmdline/cover.py:28 msgid "" "This command creates a cover page for questionnaires. All\n" " the metadata of the survey will be printed on the page." msgstr "" "Kommandoen oppretter en omslagsside for spørreskjema. All\n" "metadataen for spørreundersøkelen vil bli skrevet på siden." #: ../sdaps/cmdline/cover.py:31 #, fuzzy, python-format msgid "Filename to store the data to (default: cover_%%i.pdf)" msgstr "Filnavn å lagre data i (forvalg: cover_%%i.pdf)" #: ../sdaps/cmdline/csvdata.py:34 #, fuzzy msgid "Import or export data to/from CSV files." msgstr "Importer eller eksporter data fra/til CSV-filer." #: ../sdaps/cmdline/csvdata.py:35 msgid "" "Import or export data to/from a CSV file. The first line\n" " is a header which defines questionnaire_id and global_id, and a column\n" " for each checkbox and textfield. Note that the import is currently very\n" " limited, as you need to specifiy the questionnaire ID to select the " "sheet\n" " which should be updated." msgstr "" #: ../sdaps/cmdline/csvdata.py:44 msgid "Export data to CSV file." msgstr "Eksporter data til CSV-fil." #: ../sdaps/cmdline/csvdata.py:46 #, python-format msgid "Filename to store the data to (default: data_%%i.csv)" msgstr "" #: ../sdaps/cmdline/csvdata.py:48 msgid "The delimiter used in the CSV file (default ',')" msgstr "" #: ../sdaps/cmdline/csvdata.py:52 ../sdaps/cmdline/report.py:31 #: ../sdaps/cmdline/reporttex.py:52 msgid "Filter to only export a partial dataset." msgstr "" #: ../sdaps/cmdline/csvdata.py:54 msgid "Export images of freeform fields." msgstr "" #: ../sdaps/cmdline/csvdata.py:60 msgid "Export an image for each question that includes all boxes." msgstr "" #: ../sdaps/cmdline/csvdata.py:66 msgid "Export the recognition quality for each checkbox." msgstr "" #: ../sdaps/cmdline/csvdata.py:74 msgid "Import data to from a CSV file." msgstr "Importer data fra ei CSV-fil." #: ../sdaps/cmdline/csvdata.py:76 msgid "The file to import." msgstr "Fil å importere." #: ../sdaps/cmdline/gui.py:28 #, fuzzy msgid "Launch a GUI. You can view and alter the (recognized) answers with it." msgstr "" "Start et grafisk grensesnitt. Du kan vise og endre (gjenkjente) svar i det." #: ../sdaps/cmdline/gui.py:29 msgid "" "This command launches a graphical user interface that can\n" " be used to correct answers. You need to run \"recognize\" before using " "it.\n" " " msgstr "" #: ../sdaps/cmdline/gui.py:34 msgid "Filter to only show a partial dataset." msgstr "Filtrer for å kun vise et delvist datasett." #: ../sdaps/cmdline/ids.py:29 msgid "Export and import questionnaire IDs." msgstr "Eksporter og importer spørreskjema-ID-er." #: ../sdaps/cmdline/ids.py:30 msgid "" "This command can be used to import and export questionnaire\n" " IDs. It only makes sense in projects where such an ID is printed on the\n" " questionnaire. Note that you can also add IDs by using the stamp " "command,\n" " which will give you the PDF at the same time." msgstr "" #: ../sdaps/cmdline/ids.py:35 #, python-format msgid "Filename to store the data to (default: ids_%%i)" msgstr "" #: ../sdaps/cmdline/ids.py:38 msgid "Add IDs to the internal list from the specified file." msgstr "Legg til ID-er fra den interne listen fra den angitt fila." #: ../sdaps/cmdline/info.py:28 msgid "Display and modify metadata of project." msgstr "Vis og endre metadata tilhørende prosjekt." #: ../sdaps/cmdline/info.py:29 msgid "" "This command lets you modify the metadata of the SDAPS\n" " project. You can modify, add and remove arbitrary keys that will be " "printed\n" " on the report. The only key that always exist is \"title\".\n" " If no key is given then a list of defined keys is printed." msgstr "" #: ../sdaps/cmdline/info.py:36 msgid "Delete the key and value pair." msgstr "Slett nøkkelen og verdiparret." #: ../sdaps/cmdline/info.py:40 msgid "The key to display or modify." msgstr "Nøkkelen å vise eller endre." #: ../sdaps/cmdline/info.py:44 msgid "Set the given key to this value." msgstr "Set angitt nøkkel til denne verdien." #: ../sdaps/cmdline/info.py:69 msgid "Existing fields:\n" msgstr "Eksisterende felter:\n" #: ../sdaps/cmdline/recognize.py:28 msgid "Run the optical mark recognition." msgstr "Kjør optisk merkegjenkjenning." #: ../sdaps/cmdline/recognize.py:29 msgid "" "Iterates over all images and runs the optical mark\n" " recognition. It will reevaluate sheets even if \"recognize\" has " "already\n" " run or manual changes were made." msgstr "" #: ../sdaps/cmdline/recognize.py:34 msgid "" "Only identify the page properties, but don't recognize the checkbox states." msgstr "" "Kun identifiser sideegenskapene, men ikke gjenkjenn avkryssningsboksvalgene." #: ../sdaps/cmdline/recognize.py:39 msgid "" "Rerun the recognition for all pages. The default is to skip all pages that " "were recognized or verified already." msgstr "" #: ../sdaps/cmdline/reorder.py:26 msgid "Reorder pages according to questionnaire ID." msgstr "" #: ../sdaps/cmdline/reorder.py:27 msgid "" "This command reorders all pages according to the already\n" " recognized questionnaire ID. To use it add all the files to the " "project,\n" " then run a partial recognition using \"recognize --identify\". After " "this\n" " you have to run this command to reorder the data for the real " "recognition.\n" " " msgstr "" #: ../sdaps/cmdline/report.py:26 msgid "Create a PDF report." msgstr "Opprett en PDF-rapport." #: ../sdaps/cmdline/report.py:27 msgid "" "This command creates a PDF report using reportlab that\n" " contains statistics and if selected the freeform fields." msgstr "" #: ../sdaps/cmdline/report.py:33 msgid "Create a filtered report for every checkbox." msgstr "Opprett en filtrert rapport for hver avkryssningsboks." #: ../sdaps/cmdline/report.py:36 msgid "Short format (without freeform text fields)." msgstr "" #: ../sdaps/cmdline/report.py:41 msgid "Detailed output. (default)" msgstr "Detaljert utdata. (forvalg)" #: ../sdaps/cmdline/report.py:47 ../sdaps/cmdline/reporttex.py:30 msgid "" "Do not include original images in the report. This is useful if there are " "privacy concerns." msgstr "" #: ../sdaps/cmdline/report.py:52 ../sdaps/cmdline/reporttex.py:35 msgid "Do not use substitutions instead of images." msgstr "" #: ../sdaps/cmdline/report.py:58 ../sdaps/cmdline/reporttex.py:46 msgid "The paper size used for the output (default: locale dependent)" msgstr "" #: ../sdaps/cmdline/report.py:61 ../sdaps/cmdline/reporttex.py:49 #, python-format msgid "Filename to store the data to (default: report_%%i.pdf)" msgstr "" #: ../sdaps/cmdline/reporttex.py:26 msgid "Create a PDF report using LaTeX." msgstr "Opprett en PDF-rapport ved bruk av LaTeX." #: ../sdaps/cmdline/reporttex.py:27 msgid "" "This command creates a PDF report using LaTeX that\n" " contains statistics and freeform fields." msgstr "" #: ../sdaps/cmdline/reporttex.py:41 msgid "Save the generated TeX files instead of the final PDF." msgstr "" #: ../sdaps/cmdline/reset.py:26 msgid "Reset project into original state" msgstr "" #: ../sdaps/cmdline/reset.py:27 msgid "" "This command does a full reset of the project. All data\n" " will be discarded and only the empty project is left.\n" " " msgstr "" #: ../sdaps/cmdline/setup.py:27 msgid "Create a new survey using a LaTeX document." msgstr "" #: ../sdaps/cmdline/setup.py:28 msgid "" "Create a new survey from a LaTeX document. You need to\n" " be using the SDAPS class. All the metadata and options for the project\n" " can be set inside the LaTeX document." msgstr "" #: ../sdaps/cmdline/setup.py:33 msgid "The LaTeX Document" msgstr "LaTeX-dokumentet" #: ../sdaps/cmdline/setup.py:35 msgid "" "Additional files that are required by the LaTeX document and need to be " "copied into the project directory." msgstr "" #: ../sdaps/cmdline/setup.py:39 msgid "Additional questions that are not part of the questionnaire." msgstr "Tilleggsspørsmål som ikke er del av spørreskjemaet." #: ../sdaps/cmdline/stamp.py:26 msgid "Add marks for automatic processing." msgstr "Legg til merker for automatisk behandling." #: ../sdaps/cmdline/stamp.py:27 msgid "" "This command creates the printable document. Depending on\n" " the projects setting you are required to specifiy a source for " "questionnaire\n" " IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:33 msgid "" "If using questionnaire IDs, create N questionnaires with randomized IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:36 msgid "" "If using questionnaire IDs, create questionnaires from the IDs read from the " "specified file." msgstr "" #: ../sdaps/cmdline/stamp.py:39 msgid "If using questionnaire IDs, create questionnaires for all stored IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:42 #, python-format msgid "Filename to store the data to (default: stamp_%%i.pdf)" msgstr "Filnavn å lagre data til (forvalg: stamp_%%i.pdf)" #: ../sdaps/convert/__init__.py:37 #, python-format msgid "Could not apply 3D-transformation to image '%s', page %i!" msgstr "" #: ../sdaps/cover/__init__.py:40 #, fuzzy msgid "SDAPS questionnaire" msgstr "Spørreskjema-ID: %i" #: ../sdaps/csvdata/buddies.py:77 #, python-format msgid "Not importing unknown questionnaire ID \"%s\"" msgstr "" #: ../sdaps/gui/__init__.py:59 msgid "" "The survey does not have any images! Please add images (and run recognize) " "before using the GUI." msgstr "" #: ../sdaps/gui/__init__.py:211 msgid "Page|Invalid" msgstr "" #: ../sdaps/gui/__init__.py:214 #, python-format msgid "Page %i" msgid_plural "Page %i" msgstr[0] "" msgstr[1] "" #: ../sdaps/gui/__init__.py:256 msgid "Copyright © 2007-2014 The SDAPS Authors" msgstr "" #: ../sdaps/gui/__init__.py:258 msgid "Scripts for data acquisition with paper based surveys" msgstr "" #: ../sdaps/gui/__init__.py:259 msgid "http://sdaps.org" msgstr "" #: ../sdaps/gui/__init__.py:260 msgid "translator-credits" msgstr "Allan Nordhøy " #: ../sdaps/gui/__init__.py:305 #, python-format msgid " of %i" msgstr " av %i" #: ../sdaps/gui/__init__.py:306 #, python-format msgid "Recognition Quality: %.2f" msgstr "Gjenkjennelseskvalitet: %.2f" #: ../sdaps/gui/__init__.py:322 msgid "" "You have reached the first page of the survey. Would you like to go to the " "last page?" msgstr "" "Du har nådd førstesiden av spørreundersøkelsen. Ønsker du å gå til den siste " "siden?" #: ../sdaps/gui/__init__.py:324 msgid "Go to last page" msgstr "Gå til siste side" #: ../sdaps/gui/__init__.py:346 msgid "" "You have reached the last page of the survey. Would you like to go to the " "first page?" msgstr "" "Du har nådd den siste siden av spørreundersøkelsen. Ønsker du å gå til " "førstesiden?" #: ../sdaps/gui/__init__.py:348 msgid "Go to first page" msgstr "Gå til første side" #: ../sdaps/gui/__init__.py:457 msgid "Close without saving" msgstr "Lukk uten å lagre" #: ../sdaps/gui/__init__.py:461 msgid "" "Save the project before closing?\n" "\n" "If you do not save you may loose data." msgstr "" #: ../sdaps/gui/main_window.ui.h:1 msgid "Forward" msgstr "Neste side" #: ../sdaps/gui/main_window.ui.h:2 msgid "Previous" msgstr "Forrige" #: ../sdaps/gui/main_window.ui.h:3 msgid "Zoom In" msgstr "Forstørr" #: ../sdaps/gui/main_window.ui.h:4 msgid "Zoom Out" msgstr "Forminsk" #: ../sdaps/gui/main_window.ui.h:5 msgid "SDAPS" msgstr "SDAPS" #: ../sdaps/gui/main_window.ui.h:6 msgid "_File" msgstr "_FIl" #: ../sdaps/gui/main_window.ui.h:7 msgid "_View" msgstr "_Vis" #: ../sdaps/gui/main_window.ui.h:8 msgid "_Help" msgstr "_Hjelp" #: ../sdaps/gui/main_window.ui.h:9 #, fuzzy msgid "Page Rotated" msgstr "Side rotert" #: ../sdaps/gui/main_window.ui.h:10 msgid "Sort by Quality" msgstr "Sorter etter kvalitet" #: ../sdaps/gui/main_window.ui.h:11 msgid "label" msgstr "etikett" #: ../sdaps/gui/widget_buddies.py:56 msgid "Global Properties" msgstr "" #: ../sdaps/gui/widget_buddies.py:60 msgid "Sheet valid" msgstr "" #: ../sdaps/gui/widget_buddies.py:61 msgid "Sheet Verified" msgstr "" #: ../sdaps/gui/widget_buddies.py:62 msgid "Page Verified" msgstr "" #: ../sdaps/gui/widget_buddies.py:63 msgid "Empty" msgstr "Tom" #: ../sdaps/gui/widget_buddies.py:75 ../sdaps/gui/widget_buddies.py:105 msgid "Questionnaire ID: " msgstr "Spørreskjema-ID:" #: ../sdaps/image/__init__.py:47 msgid "" "It appears you have not build the C extension. Please run \"./setup.py build" "\" in the toplevel directory." msgstr "" #: ../sdaps/utils/latex.py:29 msgid "" "The latex character map is missing! Please build it using the supplied tool " "(create-latexmap.py)." msgstr "" #: ../sdaps/utils/latex.py:69 msgid "" "Generated string for LaTeX contains unicode characters. This may not work " "correctly and could mean the LaTeX character map needs to be updated." msgstr "" #: ../sdaps/utils/opencv.py:35 msgid "Cannot convert PDF files as poppler is not installed or usable!" msgstr "" #: ../sdaps/utils/opencv.py:44 msgid "File does not exist" msgstr "" #. The old code used to first filter, and then run; but that is #. a bit ineffective in a way #: ../sdaps/model/survey.py:386 #, python-format msgid "%i sheet" msgid_plural "%i sheets" msgstr[0] "%i ark" msgstr[1] "%i ark" #: ../sdaps/model/survey.py:402 #, python-format msgid "Processed %i of %i sheets, took %f seconds" msgstr "" #: ../sdaps/model/survey.py:449 msgid "" "A questionnaire that is printed in duplex needs an even amount of pages!" msgstr "" #: ../sdaps/model/survey.py:453 msgid "" "The 'classic' style only supports a maximum of six pages! Use the 'code128' " "style if you require more pages." msgstr "" #: ../sdaps/model/survey.py:466 msgid "IDs need to be integers in \"classic\" style!" msgstr "" #: ../sdaps/model/survey.py:472 #, python-format msgid "Invalid character %s in questionnaire ID \"%s\" in \"code128\" style!" msgstr "" #: ../sdaps/model/survey.py:476 msgid "" "SDAPS cannot draw a questionnaire ID with the \"custom\" style. Do this " "yourself somehow!" msgstr "" #. in simplex mode every page will have a matrix; it might be a None #. matrix though #: ../sdaps/recognize/buddies.py:71 #, python-format msgid "%s, %i: Matrix not recognized." msgstr "" #: ../sdaps/recognize/buddies.py:80 #, python-format msgid "%s, %i: Rotation not found." msgstr "" #. Copy the rotation over (if required) and print warning if the rotation is unknown #: ../sdaps/recognize/buddies.py:84 #, python-format msgid "Neither %s, %i or %s, %i has a known rotation!" msgstr "" #: ../sdaps/recognize/buddies.py:96 #, python-format msgid "%s, %i: Matrix not recognized (again)." msgstr "" #: ../sdaps/recognize/buddies.py:110 #, python-format msgid "%s, %i: Could not get page number." msgstr "" #. Whoa, that should not happen. #: ../sdaps/recognize/buddies.py:130 #, python-format msgid "Neither %s, %i or %s, %i has a known page number!" msgstr "" #. We don't touch the ignore flag in this case #. Simply print a message as this should *never* happen #: ../sdaps/recognize/buddies.py:141 #, python-format msgid "" "Got a simplex document where two adjacent pages had a known page number. " "This should never happen as even simplex scans are converted to duplex by " "inserting dummy pages. Maybe you did a simplex scan but added it in duplex " "mode? The pages in question are %s, %i and %s, %i." msgstr "" #: ../sdaps/recognize/buddies.py:158 #, python-format msgid "Images %s, %i and %s, %i do not have consecutive page numbers!" msgstr "" #: ../sdaps/recognize/buddies.py:174 #, python-format msgid "No page number for page %s, %i exists." msgstr "Sidenummeret for siden %s, %i finnes." #: ../sdaps/recognize/buddies.py:179 #, python-format msgid "Page number for page %s, %i already used by another image." msgstr "Sidenummeret for siden %s, %i allerede i bruk av et annet bilde." #: ../sdaps/recognize/buddies.py:185 #, fuzzy, python-format msgid "Page number %i for page %s, %i is out of range." msgstr "Sidenummer %i for siden %s, %i er utenfor rekkevidden." #: ../sdaps/recognize/buddies.py:202 #, python-format msgid "%s, %i: Could not read survey ID, but should be able to." msgstr "" #: ../sdaps/recognize/buddies.py:206 #, python-format msgid "Could not read survey ID of either %s, %i or %s, %i!" msgstr "" #. Broken survey ID ... #: ../sdaps/recognize/buddies.py:213 #, python-format msgid "Got a wrong survey ID (%s, %i)! It is %s, but should be %i." msgstr "" #: ../sdaps/recognize/buddies.py:235 #, python-format msgid "%s, %i: Could not read questionnaire ID, but should be able to." msgstr "" #: ../sdaps/recognize/buddies.py:241 #, python-format msgid "Could not read questionnaire ID of either %s, %i or %s, %i!" msgstr "" #: ../sdaps/recognize/buddies.py:271 msgid "" "Got different IDs on different pages for at least one sheet! Do *NOT* try to " "use filters with this survey! You have to run a \"reorder\" step for this to " "work properly!" msgstr "" #: ../sdaps/recognize/buddies.py:326 msgid "No style buddy loaded. This needs to be done for the \"custom\" style!" msgstr "" #: ../sdaps/report/answers.py:188 #, python-format msgid "Answers: %i" msgstr "Svar: %i" #: ../sdaps/report/answers.py:190 #, python-format msgid "Mean: %.2f" msgstr "Gjennomsnitt: %.2f" #: ../sdaps/report/answers.py:192 #, python-format msgid "Standard Deviation: %.2f" msgstr "Standardavvik: %.2f" #: ../sdaps/report/__init__.py:75 ../sdaps/reporttex/__init__.py:140 msgid "Turned in Questionnaires" msgstr "Innleverte spørreskjema" #: ../sdaps/report/__init__.py:92 ../sdaps/reporttex/__init__.py:139 msgid "sdaps report" msgstr "" #: ../sdaps/reset/__init__.py:29 msgid "Removing stored data..." msgstr "Fjerner lagret data…" #: ../sdaps/setup/buddies.py:62 #, python-format msgid "Head %(l0)i got no title." msgstr "" #: ../sdaps/setup/buddies.py:74 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no question." msgstr "" #: ../sdaps/setup/buddies.py:114 #, python-format msgid "Error in question \"%s\"" msgstr "Feil i spørsmålet \"%s\"" #: ../sdaps/setup/buddies.py:118 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no boxes." msgstr "" #: ../sdaps/setup/buddies.py:167 #, python-format msgid "%(class)s %(l0)i.%(l1)i lower box out of range." msgstr "" #: ../sdaps/setup/buddies.py:172 #, python-format msgid "%(class)s %(l0)i.%(l1)i upper box out of range." msgstr "" #: ../sdaps/setup/buddies.py:177 #, python-format msgid "%(class)s %(l0)i.%(l1)i lower box not before upper box." msgstr "" #: ../sdaps/setup/buddies.py:213 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly two answers." msgstr "" #: ../sdaps/setup/buddies.py:234 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly one box." msgstr "" #: ../sdaps/stamp/__init__.py:38 msgid "" "You may not specify the number of sheets for this survey. All questionnaires " "will be identical as the survey has been configured to not use questionnaire " "IDs for each sheet." msgstr "" #: ../sdaps/stamp/__init__.py:76 msgid "" "This survey has been configured to use questionnaire IDs. Each questionnaire " "will be unique. You need to use on of the options to add new IDs or use the " "existing ones." msgstr "" #: ../sdaps/stamp/latex.py:18 msgid "" "There should be no need to stamp a SDAPS Project that uses LaTeX and does " "not have different questionnaire IDs printed on each sheet.\n" "I am going to do so anyways." msgstr "" #: ../sdaps/stamp/latex.py:26 #, python-format msgid "Running %s now twice to generate the stamped questionnaire." msgstr "" #: ../sdaps/stamp/latex.py:30 ../sdaps/setuptex/__init__.py:107 #: ../sdaps/setuptex/__init__.py:148 ../sdaps/reporttex/__init__.py:162 #, python-format msgid "Error running \"%s\" to compile the LaTeX file." msgstr "" #: ../sdaps/stamp/latex.py:36 #, python-format msgid "" "An error occured during creation of the report. Temporary files left in '%s'." msgstr "" #: ../sdaps/setuptex/__init__.py:46 msgid "The survey directory already exists." msgstr "" #: ../sdaps/setuptex/__init__.py:51 #, python-format msgid "Unknown file type (%s). questionnaire_tex should be of type text/x-tex." msgstr "" #: ../sdaps/setuptex/__init__.py:52 msgid "Will keep going, but expect failure!" msgstr "" #: ../sdaps/setuptex/__init__.py:57 #, python-format msgid "Unknown file type (%s). additionalqobjects should be text/plain." msgstr "" #: ../sdaps/setuptex/__init__.py:103 ../sdaps/setuptex/__init__.py:143 #, python-format msgid "Running %s now twice to generate the questionnaire." msgstr "" #: ../sdaps/setuptex/__init__.py:122 msgid "Caught an Exception while parsing the SDAPS file. The current state is:" msgstr "" #: ../sdaps/setuptex/__init__.py:136 msgid "" "Some combination of options and project properties do not work. Aborted " "Setup." msgstr "" #: ../sdaps/setuptex/__init__.py:162 msgid "" "An error occured in the setup routine. The survey directory still exists. " "You can for example check the questionnaire.log file for LaTeX compile " "errors." msgstr "" #: ../sdaps/reporttex/__init__.py:107 msgid "author|Unknown" msgstr "forfatter|Ukjent" #: ../sdaps/reporttex/__init__.py:138 msgid "tex language|english" msgstr "" #: ../sdaps/reporttex/__init__.py:155 #, python-format msgid "The TeX project with the report data is located at '%s'." msgstr "" #: ../sdaps/reporttex/__init__.py:158 #, python-format msgid "Running %s now twice to generate the report." msgstr "" #: ../sdaps/reporttex/__init__.py:168 #, python-format msgid "An occured during creation of the report. Temporary files left in '%s'." msgstr "" #~ msgid "%f seconds per sheet" #~ msgstr "%f sekunder per ark" #~ msgid "The ODT Document" #~ msgstr "ODT-dokumentet" #~ msgid "PDF export of the ODT document" #~ msgstr "PDF-eksport av ODT-dokumentet" #~ msgid "Survey-ID: %i" #~ msgstr "Spørreundersøkelses-ID: %i" #~ msgid "Questionnaire-ID: %i" #~ msgstr "Spørreskjema-ID: %i" #, fuzzy #~ msgid "You need to have either PDFtk or pyPdf installed. PDFtk is faster." #~ msgstr "Du må ha enten PDFtk eller PyPdf installert. PDFtk er raskest." #, fuzzy #~ msgid "Marking using PDFtk" #~ msgstr "Flett ved bruk av PDFtk" sdaps-1.9.8/po/nl.po0000644000175000000660000007201613421045054014772 0ustar benjaminlock00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:10+0100\n" "PO-Revision-Date: 2019-01-18 18:21+0000\n" "Last-Translator: Allan Nordhøy \n" "Language-Team: Dutch \n" "Language: nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 3.4-dev\n" #: ../sdaps/script.py:41 msgid "SDAPS -- Paper based survey tool." msgstr "SDAPS -- Hulpmiddel voor bevragingen op papier." #: ../sdaps/script.py:45 msgid "command list|Commands:" msgstr "commandolijst|Commando's:" #: ../sdaps/script.py:50 msgid "project directory|The SDAPS project." msgstr "projectfolder|Het SDAPS-project." #: ../sdaps/add/__init__.py:55 #, python-format msgid "" "Invalid input file %s. You need to specify a (multipage) monochrome TIFF as " "input." msgstr "" "Ongeldig invoerbestand %s. Gelieve een monochrome TIFF (van meerdere " "pagina's) als invoer op te geven." #: ../sdaps/add/__init__.py:67 #, python-format msgid "" "Not adding %s because it has a wrong page count (needs to be a mulitple of " "%i)." msgstr "" "%s werd niet toegevoegd, omdat het paginatotaal niet klopt (dit dient een " "meervoud te zijn van %i)." #: ../sdaps/boxgallery/__init__.py:108 #, python-format msgid "Rendering boxgallery for metric \"%s\"." msgstr "Opmaak van vakjesgalerij voor meetwaarde \"%s\"." #: ../sdaps/log.py:37 msgid "Warning: " msgstr "Waarschuwing: " #: ../sdaps/log.py:41 msgid "Error: " msgstr "Foutmelding: " #: ../sdaps/cmdline/add.py:31 msgid "Add scanned questionnaires to the survey." msgstr "Ingescande vragenlijsten toevoegen aan de bevraging." #: ../sdaps/cmdline/add.py:32 msgid "" "This command is used to add scanned images to the survey.\n" " The image data needs to be a (multipage) 300dpi monochrome TIFF file. " "You\n" " may choose not to copy the data into the project directory. In that " "case\n" " the data will be referenced using a relative path." msgstr "" "Dit commando wordt benut om ingescande afbeeldingen aan de bevraging toe te " "voegen.\n" " De afbeelding dient een 300dpi monochroom TIFF-bestand (van meerdere " "pagina's) te zijn.\n" " Men kan verkiezen van de data niet in de projectfolder te kopiëren.\n" " In dat geval, zal naar de data worden gerefereerd met een relatief pad." #: ../sdaps/cmdline/add.py:38 msgid "Convert given files and add the result." msgstr "Converteer de gegeven bestanden en voeg het resultaat toe." #: ../sdaps/cmdline/add.py:43 msgid "" "Do a 3D-transformation after finding the corner marks. If the\n" " corner marks are not found then the image will be added as-is." msgstr "" "Voer een 3D-transofrmatie uit na het vinden van de hoekmarkeringen. \n" " De afbeelding wordt ongewijzigd opgenomen indien de hoekmarkeringen " "niet werden gevonden." #: ../sdaps/cmdline/add.py:49 msgid "" "Force adding the images even if the page count is wrong (only use if you " "know what you are doing)." msgstr "" "Forceer het toevoegen van de afbeeldingen, zelfs als het paginatotaal niet " "klopt (enkel gebruiken wanneer men weet wat men doet)." #: ../sdaps/cmdline/add.py:53 msgid "Copy the files into the directory (default)." msgstr "Kopieer de bestanden in de folder (standaard)." #: ../sdaps/cmdline/add.py:58 msgid "Do not copy the files into the directory." msgstr "Kopieer de bestanden niet in de folder." #: ../sdaps/cmdline/add.py:62 msgid "" "Images contain a duplex scan of a simplex questionnaire (default: simplex " "scan)." msgstr "" "De afbeeldingen bevatten een tweezijdige scan van een enkelzijdige " "vragenlijst (standaard: enkelzijdige scan)." #: ../sdaps/cmdline/add.py:68 ../sdaps/cmdline/convert.py:48 msgid "A number of TIFF image files." msgstr "Één of meerdere TIFF-bestanden." #: ../sdaps/cmdline/add.py:94 msgid "The --no-copy option is not compatible with --convert!" msgstr "De --no-copy optie is niet verenigbaar met --convert!" #: ../sdaps/cmdline/add.py:103 msgid "Converting input files into a single temporary file." msgstr "De invoerbestanden worden naar één enkel tijdelijk bestand omgezet." #: ../sdaps/cmdline/add.py:115 msgid "" "The page count of the created temporary file does not work with this survey." msgstr "" "Het paginatotaal van het aangemaakt tijdelijk bestand past niet bij deze " "bevraging." #: ../sdaps/cmdline/add.py:120 msgid "Running the conversion failed." msgstr "Het omzetten liep fout." #: ../sdaps/cmdline/add.py:126 #, python-format msgid "Processing %s" msgstr "%s wordt verwerkt" #: ../sdaps/cmdline/add.py:130 ../sdaps/reset/__init__.py:33 msgid "Done" msgstr "Klaar" #: ../sdaps/cmdline/annotate.py:28 msgid "Annotate the questionnaire and show the recognized positions." msgstr "Markeer de vragenlijst en toon de herkende posities." #: ../sdaps/cmdline/annotate.py:29 msgid "" "This command is mainly a debug utility. It creates an\n" " annotated version of the questionnaire, with the information that SDAPS\n" " knows about it overlayed on top." msgstr "" "Dit commando is hoofdzakelijk een hulpmiddel om fouten op te sporen.\n" " Het maakt een versie van de vragenlijst aan, waarbij die wordt " "overschreven\n" " met de door SDAPS herkende informatie." #: ../sdaps/cmdline/boxgallery.py:31 msgid "Create PDFs with boxes sorted by the detection heuristics." msgstr "Maak PDF's met vakjes gesorteerd naar de detectieheuristiek." #: ../sdaps/cmdline/boxgallery.py:32 msgid "" "SDAPS uses multiple heuristics to detect determine the\n" " state of checkboxes. There is a list for each heuristic giving the " "expected\n" " state and the quality of the value (see defs.py). Using this command a " "PDF\n" " will be created for each of the heuristics so that one can adjust the\n" " values." msgstr "" "SDAPS gebruikt meervoudige heuristieken om de toestand van de aanvinkvakjes " "te bepalen.\n" " Voor elke heuristiek wordt de verwachte toestand en de kwaliteit van de " "waarde in een lijst opgenomen (zie defs.py).\n" " Met behulp van dit commando wordt voor elk van de heuristieken een PDF " "aangemaakt om de waarden te kunnen aanpassen." #: ../sdaps/cmdline/boxgallery.py:40 msgid "" "Reruns part of the recognition process and retrieves debug images from this " "step." msgstr "" "Voert het herkenningsproces gedeeltelijk opnieuw uit, waarbij afbeeldingen " "worden gemaakt voor foutdiagnose." #: ../sdaps/cmdline/convert.py:30 msgid "Convert a set of images to the correct image format." msgstr "Converteer een groep afbeeldingen naar het correcte afbeeldingsformaat." #: ../sdaps/cmdline/convert.py:31 msgid "" "This command can be used if you scanned files in something\n" " other than the expected monochrome TIFF mode. All given files will\n" " be loaded, converted to monochrome and stored in a multipage 1bpp\n" " TIFF file. Optionally, you can select \"3D transformation\"\\ ,which " "may facilitate\n" " working with photos of questionnaires instead of scans." msgstr "" "Dit commando kan worden gebruikt wanneer de bestanden in een ander formaat " "werden gescand dan het verwachte monochroom TIFF-formaat.\n" " Alle betreffende bestanden zullen worden geladen, omgezet naar " "monochroom en bewaard in een 1bpp TIFF-bestand van meerdere pagina's.\n" " Optioneel kan men ook \"3D-transformatie* selecteren, wat het werken " "met foto's in plaats van scans van vragenlijsten eenvoudiger maakt." #: ../sdaps/cmdline/convert.py:38 msgid "" "Do a 3D-transformation after finding the corner marks.\n" " If they are not found, the image will be processed as-is." msgstr "" "Voer een 3D-transformatie uit na het vinden van de hoekmarkeringen.\n" " Indien deze niet worden gevonden, wordt de afbeelding ongewijzigd " "verwerkt." #: ../sdaps/cmdline/convert.py:44 msgid "The location of the output file." msgstr "De locatie van het uitvoerbestand." #: ../sdaps/cmdline/convert.py:57 msgid "No output filename specified!" msgstr "Er werd geen bestandsnaam voor de uitvoer opgegeven!" #: ../sdaps/cmdline/cover.py:27 msgid "Create a cover for the questionnaires." msgstr "Maak een voorblad voor de vragenlijsten aan." #: ../sdaps/cmdline/cover.py:28 msgid "" "This command creates a cover page for questionnaires. All\n" " the metadata of the survey will be printed on the page." msgstr "" "Dit commando maakt een voorblad voor de vragenlijsten.\n" " Het voorblad bevat alle metadata van de bevraging." #: ../sdaps/cmdline/cover.py:31 #, python-format msgid "Filename to store the data to (default: cover_%%i.pdf)" msgstr "Bestandsnaam voor het opslaan van de data (standaard: cover_%%i.pdf)" #: ../sdaps/cmdline/csvdata.py:34 msgid "Import or export data to/from CSV files." msgstr "Importeer of exporteer data naar/van CSV-bestanden." #: ../sdaps/cmdline/csvdata.py:35 msgid "" "Import or export data to/from a CSV file. The first line\n" " is a header which defines questionnaire_id and global_id, and a column\n" " for each checkbox and textfield. Note that the import is currently very\n" " limited, as you need to specifiy the questionnaire ID to select the " "sheet\n" " which should be updated." msgstr "" "Importeer of exporteer data van/naar een CSV-bestand. Hierbij is de eerste " "lijn\n" " een kopregel met questionnaire_id, global_id evenals een dubbelpunt \n" " voor elk aanvinkvakje en tekstveld. De importfunctie werkt momenteel " "slechts\n" " gedeeltelijk; men dient de vragenlijst-ID op te geven om het blad te " "selecteren\n" " dat dient te worden geactualiseerd." #: ../sdaps/cmdline/csvdata.py:44 msgid "Export data to CSV file." msgstr "Data in CSV-formaat exporteren." #: ../sdaps/cmdline/csvdata.py:46 #, python-format msgid "Filename to store the data to (default: data_%%i.csv)" msgstr "Bestandsnaam voor het opslaan in CSV-formaat (standaard: data_%%i.csv)" #: ../sdaps/cmdline/csvdata.py:48 msgid "The delimiter used in the CSV file (default ',')" msgstr "Scheidingsteken voor gebruik in het CSV-bestand (standaard ',')" #: ../sdaps/cmdline/csvdata.py:52 ../sdaps/cmdline/report.py:31 #: ../sdaps/cmdline/reporttex.py:52 msgid "Filter to only export a partial dataset." msgstr "Filter om enkel een gedeelte van de data te exporteren." #: ../sdaps/cmdline/csvdata.py:54 msgid "Export images of freeform fields." msgstr "Exporteer de afbeeldingen van vrije tekstvelden." #: ../sdaps/cmdline/csvdata.py:60 msgid "Export an image for each question that includes all boxes." msgstr "Exporteer een afbeelding van elke vraag met alle vakjes." #: ../sdaps/cmdline/csvdata.py:66 msgid "Export the recognition quality for each checkbox." msgstr "Exporteer de herkenningskwaliteit van elk vakje." #: ../sdaps/cmdline/csvdata.py:74 msgid "Import data to from a CSV file." msgstr "Importeer data uit een CSV-bestand." #: ../sdaps/cmdline/csvdata.py:76 msgid "The file to import." msgstr "Het te importeren bestand." #: ../sdaps/cmdline/gui.py:28 msgid "Launch a GUI. You can view and alter the (recognized) answers with it." msgstr "" "Start een grafische omgeving. De (herkende) antwoorden kunnen ermee worden " "bekeken of gewijzigd." #: ../sdaps/cmdline/gui.py:29 msgid "" "This command launches a graphical user interface that can\n" " be used to correct answers. You need to run \"recognize\" before using " "it.\n" " " msgstr "" "Dit commando start een grafische gebruiksomgeving dat\n" " men kan aanwenden voor het verbeteren van antwoorden.\n" " Voor gebruik dient men eerst \"herken\" uit te voeren.\n" " " #: ../sdaps/cmdline/gui.py:34 msgid "Filter to only show a partial dataset." msgstr "Filter om enkel een gedeelte van de data te zien." #: ../sdaps/cmdline/ids.py:29 msgid "Export and import questionnaire IDs." msgstr "Exporteer en importeer vragenlijst-ID's." #: ../sdaps/cmdline/ids.py:30 msgid "" "This command can be used to import and export questionnaire\n" " IDs. It only makes sense in projects where such an ID is printed on the\n" " questionnaire. Note that you can also add IDs by using the stamp " "command,\n" " which will give you the PDF at the same time." msgstr "" #: ../sdaps/cmdline/ids.py:35 #, python-format msgid "Filename to store the data to (default: ids_%%i)" msgstr "" #: ../sdaps/cmdline/ids.py:38 msgid "Add IDs to the internal list from the specified file." msgstr "" #: ../sdaps/cmdline/info.py:28 msgid "Display and modify metadata of project." msgstr "" #: ../sdaps/cmdline/info.py:29 msgid "" "This command lets you modify the metadata of the SDAPS\n" " project. You can modify, add and remove arbitrary keys that will be " "printed\n" " on the report. The only key that always exist is \"title\".\n" " If no key is given then a list of defined keys is printed." msgstr "" #: ../sdaps/cmdline/info.py:36 msgid "Delete the key and value pair." msgstr "" #: ../sdaps/cmdline/info.py:40 msgid "The key to display or modify." msgstr "" #: ../sdaps/cmdline/info.py:44 msgid "Set the given key to this value." msgstr "" #: ../sdaps/cmdline/info.py:69 msgid "Existing fields:\n" msgstr "" #: ../sdaps/cmdline/recognize.py:28 msgid "Run the optical mark recognition." msgstr "" #: ../sdaps/cmdline/recognize.py:29 msgid "" "Iterates over all images and runs the optical mark\n" " recognition. It will reevaluate sheets even if \"recognize\" has " "already\n" " run or manual changes were made." msgstr "" #: ../sdaps/cmdline/recognize.py:34 msgid "" "Only identify the page properties, but don't recognize the checkbox states." msgstr "" #: ../sdaps/cmdline/recognize.py:39 msgid "" "Rerun the recognition for all pages. The default is to skip all pages that " "were recognized or verified already." msgstr "" #: ../sdaps/cmdline/reorder.py:26 msgid "Reorder pages according to questionnaire ID." msgstr "" #: ../sdaps/cmdline/reorder.py:27 msgid "" "This command reorders all pages according to the already\n" " recognized questionnaire ID. To use it add all the files to the " "project,\n" " then run a partial recognition using \"recognize --identify\". After " "this\n" " you have to run this command to reorder the data for the real " "recognition.\n" " " msgstr "" #: ../sdaps/cmdline/report.py:26 msgid "Create a PDF report." msgstr "" #: ../sdaps/cmdline/report.py:27 msgid "" "This command creates a PDF report using reportlab that\n" " contains statistics and if selected the freeform fields." msgstr "" #: ../sdaps/cmdline/report.py:33 msgid "Create a filtered report for every checkbox." msgstr "" #: ../sdaps/cmdline/report.py:36 msgid "Short format (without freeform text fields)." msgstr "" #: ../sdaps/cmdline/report.py:41 msgid "Detailed output. (default)" msgstr "" #: ../sdaps/cmdline/report.py:47 ../sdaps/cmdline/reporttex.py:30 msgid "" "Do not include original images in the report. This is useful if there are " "privacy concerns." msgstr "" #: ../sdaps/cmdline/report.py:52 ../sdaps/cmdline/reporttex.py:35 msgid "Do not use substitutions instead of images." msgstr "" #: ../sdaps/cmdline/report.py:58 ../sdaps/cmdline/reporttex.py:46 msgid "The paper size used for the output (default: locale dependent)" msgstr "" #: ../sdaps/cmdline/report.py:61 ../sdaps/cmdline/reporttex.py:49 #, python-format msgid "Filename to store the data to (default: report_%%i.pdf)" msgstr "" #: ../sdaps/cmdline/reporttex.py:26 msgid "Create a PDF report using LaTeX." msgstr "" #: ../sdaps/cmdline/reporttex.py:27 msgid "" "This command creates a PDF report using LaTeX that\n" " contains statistics and freeform fields." msgstr "" #: ../sdaps/cmdline/reporttex.py:41 msgid "Save the generated TeX files instead of the final PDF." msgstr "" #: ../sdaps/cmdline/reset.py:26 msgid "Reset project into original state" msgstr "" #: ../sdaps/cmdline/reset.py:27 msgid "" "This command does a full reset of the project. All data\n" " will be discarded and only the empty project is left.\n" " " msgstr "" #: ../sdaps/cmdline/setup.py:27 msgid "Create a new survey using a LaTeX document." msgstr "" #: ../sdaps/cmdline/setup.py:28 msgid "" "Create a new survey from a LaTeX document. You need to\n" " be using the SDAPS class. All the metadata and options for the project\n" " can be set inside the LaTeX document." msgstr "" #: ../sdaps/cmdline/setup.py:33 msgid "The LaTeX Document" msgstr "" #: ../sdaps/cmdline/setup.py:35 msgid "" "Additional files that are required by the LaTeX document and need to be " "copied into the project directory." msgstr "" #: ../sdaps/cmdline/setup.py:39 msgid "Additional questions that are not part of the questionnaire." msgstr "" #: ../sdaps/cmdline/stamp.py:26 msgid "Add marks for automatic processing." msgstr "" #: ../sdaps/cmdline/stamp.py:27 msgid "" "This command creates the printable document. Depending on\n" " the projects setting you are required to specifiy a source for " "questionnaire\n" " IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:33 msgid "" "If using questionnaire IDs, create N questionnaires with randomized IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:36 msgid "" "If using questionnaire IDs, create questionnaires from the IDs read from the " "specified file." msgstr "" #: ../sdaps/cmdline/stamp.py:39 msgid "If using questionnaire IDs, create questionnaires for all stored IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:42 #, python-format msgid "Filename to store the data to (default: stamp_%%i.pdf)" msgstr "" #: ../sdaps/convert/__init__.py:37 #, python-format msgid "Could not apply 3D-transformation to image '%s', page %i!" msgstr "" #: ../sdaps/cover/__init__.py:40 msgid "SDAPS questionnaire" msgstr "" #: ../sdaps/csvdata/buddies.py:77 #, python-format msgid "Not importing unknown questionnaire ID \"%s\"" msgstr "" #: ../sdaps/gui/__init__.py:59 msgid "" "The survey does not have any images! Please add images (and run recognize) " "before using the GUI." msgstr "" #: ../sdaps/gui/__init__.py:211 msgid "Page|Invalid" msgstr "" #: ../sdaps/gui/__init__.py:214 #, python-format msgid "Page %i" msgid_plural "Page %i" msgstr[0] "" msgstr[1] "" #: ../sdaps/gui/__init__.py:256 msgid "Copyright © 2007-2014 The SDAPS Authors" msgstr "" #: ../sdaps/gui/__init__.py:258 msgid "Scripts for data acquisition with paper based surveys" msgstr "" #: ../sdaps/gui/__init__.py:259 msgid "http://sdaps.org" msgstr "" #: ../sdaps/gui/__init__.py:260 msgid "translator-credits" msgstr "" #: ../sdaps/gui/__init__.py:305 #, python-format msgid " of %i" msgstr "" #: ../sdaps/gui/__init__.py:306 #, python-format msgid "Recognition Quality: %.2f" msgstr "" #: ../sdaps/gui/__init__.py:322 msgid "" "You have reached the first page of the survey. Would you like to go to the " "last page?" msgstr "" #: ../sdaps/gui/__init__.py:324 msgid "Go to last page" msgstr "" #: ../sdaps/gui/__init__.py:346 msgid "" "You have reached the last page of the survey. Would you like to go to the " "first page?" msgstr "" #: ../sdaps/gui/__init__.py:348 msgid "Go to first page" msgstr "" #: ../sdaps/gui/__init__.py:457 msgid "Close without saving" msgstr "" #: ../sdaps/gui/__init__.py:461 msgid "" "Save the project before closing?\n" "\n" "If you do not save you may loose data." msgstr "" #: ../sdaps/gui/main_window.ui.h:1 msgid "Forward" msgstr "" #: ../sdaps/gui/main_window.ui.h:2 msgid "Previous" msgstr "" #: ../sdaps/gui/main_window.ui.h:3 msgid "Zoom In" msgstr "" #: ../sdaps/gui/main_window.ui.h:4 msgid "Zoom Out" msgstr "" #: ../sdaps/gui/main_window.ui.h:5 msgid "SDAPS" msgstr "" #: ../sdaps/gui/main_window.ui.h:6 msgid "_File" msgstr "" #: ../sdaps/gui/main_window.ui.h:7 msgid "_View" msgstr "" #: ../sdaps/gui/main_window.ui.h:8 msgid "_Help" msgstr "" #: ../sdaps/gui/main_window.ui.h:9 msgid "Page Rotated" msgstr "" #: ../sdaps/gui/main_window.ui.h:10 msgid "Sort by Quality" msgstr "" #: ../sdaps/gui/main_window.ui.h:11 msgid "label" msgstr "" #: ../sdaps/gui/widget_buddies.py:56 msgid "Global Properties" msgstr "" #: ../sdaps/gui/widget_buddies.py:60 msgid "Sheet valid" msgstr "" #: ../sdaps/gui/widget_buddies.py:61 msgid "Sheet Verified" msgstr "" #: ../sdaps/gui/widget_buddies.py:62 msgid "Page Verified" msgstr "" #: ../sdaps/gui/widget_buddies.py:63 msgid "Empty" msgstr "" #: ../sdaps/gui/widget_buddies.py:75 ../sdaps/gui/widget_buddies.py:105 msgid "Questionnaire ID: " msgstr "" #: ../sdaps/image/__init__.py:47 msgid "" "It appears you have not build the C extension. Please run \"./setup.py build" "\" in the toplevel directory." msgstr "" #: ../sdaps/utils/latex.py:29 msgid "" "The latex character map is missing! Please build it using the supplied tool " "(create-latexmap.py)." msgstr "" #: ../sdaps/utils/latex.py:69 msgid "" "Generated string for LaTeX contains unicode characters. This may not work " "correctly and could mean the LaTeX character map needs to be updated." msgstr "" #: ../sdaps/utils/opencv.py:35 msgid "Cannot convert PDF files as poppler is not installed or usable!" msgstr "" #: ../sdaps/utils/opencv.py:44 msgid "File does not exist" msgstr "" #. The old code used to first filter, and then run; but that is #. a bit ineffective in a way #: ../sdaps/model/survey.py:386 #, python-format msgid "%i sheet" msgid_plural "%i sheets" msgstr[0] "" msgstr[1] "" #: ../sdaps/model/survey.py:402 #, python-format msgid "Processed %i of %i sheets, took %f seconds" msgstr "" #: ../sdaps/model/survey.py:449 msgid "" "A questionnaire that is printed in duplex needs an even amount of pages!" msgstr "" #: ../sdaps/model/survey.py:453 msgid "" "The 'classic' style only supports a maximum of six pages! Use the 'code128' " "style if you require more pages." msgstr "" #: ../sdaps/model/survey.py:466 msgid "IDs need to be integers in \"classic\" style!" msgstr "" #: ../sdaps/model/survey.py:472 #, python-format msgid "Invalid character %s in questionnaire ID \"%s\" in \"code128\" style!" msgstr "" #: ../sdaps/model/survey.py:476 msgid "" "SDAPS cannot draw a questionnaire ID with the \"custom\" style. Do this " "yourself somehow!" msgstr "" #. in simplex mode every page will have a matrix; it might be a None #. matrix though #: ../sdaps/recognize/buddies.py:71 #, python-format msgid "%s, %i: Matrix not recognized." msgstr "" #: ../sdaps/recognize/buddies.py:80 #, python-format msgid "%s, %i: Rotation not found." msgstr "" #. Copy the rotation over (if required) and print warning if the rotation is unknown #: ../sdaps/recognize/buddies.py:84 #, python-format msgid "Neither %s, %i or %s, %i has a known rotation!" msgstr "" #: ../sdaps/recognize/buddies.py:96 #, python-format msgid "%s, %i: Matrix not recognized (again)." msgstr "" #: ../sdaps/recognize/buddies.py:110 #, python-format msgid "%s, %i: Could not get page number." msgstr "" #. Whoa, that should not happen. #: ../sdaps/recognize/buddies.py:130 #, python-format msgid "Neither %s, %i or %s, %i has a known page number!" msgstr "" #. We don't touch the ignore flag in this case #. Simply print a message as this should *never* happen #: ../sdaps/recognize/buddies.py:141 #, python-format msgid "" "Got a simplex document where two adjacent pages had a known page number. " "This should never happen as even simplex scans are converted to duplex by " "inserting dummy pages. Maybe you did a simplex scan but added it in duplex " "mode? The pages in question are %s, %i and %s, %i." msgstr "" #: ../sdaps/recognize/buddies.py:158 #, python-format msgid "Images %s, %i and %s, %i do not have consecutive page numbers!" msgstr "" #: ../sdaps/recognize/buddies.py:174 #, python-format msgid "No page number for page %s, %i exists." msgstr "" #: ../sdaps/recognize/buddies.py:179 #, python-format msgid "Page number for page %s, %i already used by another image." msgstr "" #: ../sdaps/recognize/buddies.py:185 #, python-format msgid "Page number %i for page %s, %i is out of range." msgstr "" #: ../sdaps/recognize/buddies.py:202 #, python-format msgid "%s, %i: Could not read survey ID, but should be able to." msgstr "" #: ../sdaps/recognize/buddies.py:206 #, python-format msgid "Could not read survey ID of either %s, %i or %s, %i!" msgstr "" #. Broken survey ID ... #: ../sdaps/recognize/buddies.py:213 #, python-format msgid "Got a wrong survey ID (%s, %i)! It is %s, but should be %i." msgstr "" #: ../sdaps/recognize/buddies.py:235 #, python-format msgid "%s, %i: Could not read questionnaire ID, but should be able to." msgstr "" #: ../sdaps/recognize/buddies.py:241 #, python-format msgid "Could not read questionnaire ID of either %s, %i or %s, %i!" msgstr "" #: ../sdaps/recognize/buddies.py:271 msgid "" "Got different IDs on different pages for at least one sheet! Do *NOT* try to " "use filters with this survey! You have to run a \"reorder\" step for this to " "work properly!" msgstr "" #: ../sdaps/recognize/buddies.py:326 msgid "No style buddy loaded. This needs to be done for the \"custom\" style!" msgstr "" #: ../sdaps/report/answers.py:188 #, python-format msgid "Answers: %i" msgstr "" #: ../sdaps/report/answers.py:190 #, python-format msgid "Mean: %.2f" msgstr "" #: ../sdaps/report/answers.py:192 #, python-format msgid "Standard Deviation: %.2f" msgstr "" #: ../sdaps/report/__init__.py:75 ../sdaps/reporttex/__init__.py:140 msgid "Turned in Questionnaires" msgstr "" #: ../sdaps/report/__init__.py:92 ../sdaps/reporttex/__init__.py:139 msgid "sdaps report" msgstr "" #: ../sdaps/reset/__init__.py:29 msgid "Removing stored data..." msgstr "" #: ../sdaps/setup/buddies.py:62 #, python-format msgid "Head %(l0)i got no title." msgstr "" #: ../sdaps/setup/buddies.py:74 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no question." msgstr "" #: ../sdaps/setup/buddies.py:114 #, python-format msgid "Error in question \"%s\"" msgstr "" #: ../sdaps/setup/buddies.py:118 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no boxes." msgstr "" #: ../sdaps/setup/buddies.py:167 #, python-format msgid "%(class)s %(l0)i.%(l1)i lower box out of range." msgstr "" #: ../sdaps/setup/buddies.py:172 #, python-format msgid "%(class)s %(l0)i.%(l1)i upper box out of range." msgstr "" #: ../sdaps/setup/buddies.py:177 #, python-format msgid "%(class)s %(l0)i.%(l1)i lower box not before upper box." msgstr "" #: ../sdaps/setup/buddies.py:213 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly two answers." msgstr "" #: ../sdaps/setup/buddies.py:234 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly one box." msgstr "" #: ../sdaps/stamp/__init__.py:38 msgid "" "You may not specify the number of sheets for this survey. All questionnaires " "will be identical as the survey has been configured to not use questionnaire " "IDs for each sheet." msgstr "" #: ../sdaps/stamp/__init__.py:76 msgid "" "This survey has been configured to use questionnaire IDs. Each questionnaire " "will be unique. You need to use on of the options to add new IDs or use the " "existing ones." msgstr "" #: ../sdaps/stamp/latex.py:18 msgid "" "There should be no need to stamp a SDAPS Project that uses LaTeX and does " "not have different questionnaire IDs printed on each sheet.\n" "I am going to do so anyways." msgstr "" #: ../sdaps/stamp/latex.py:26 #, python-format msgid "Running %s now twice to generate the stamped questionnaire." msgstr "" #: ../sdaps/stamp/latex.py:30 ../sdaps/setuptex/__init__.py:107 #: ../sdaps/setuptex/__init__.py:148 ../sdaps/reporttex/__init__.py:162 #, python-format msgid "Error running \"%s\" to compile the LaTeX file." msgstr "" #: ../sdaps/stamp/latex.py:36 #, python-format msgid "" "An error occured during creation of the report. Temporary files left in '%s'." msgstr "" #: ../sdaps/setuptex/__init__.py:46 msgid "The survey directory already exists." msgstr "" #: ../sdaps/setuptex/__init__.py:51 #, python-format msgid "Unknown file type (%s). questionnaire_tex should be of type text/x-tex." msgstr "" #: ../sdaps/setuptex/__init__.py:52 msgid "Will keep going, but expect failure!" msgstr "" #: ../sdaps/setuptex/__init__.py:57 #, python-format msgid "Unknown file type (%s). additionalqobjects should be text/plain." msgstr "" #: ../sdaps/setuptex/__init__.py:103 ../sdaps/setuptex/__init__.py:143 #, python-format msgid "Running %s now twice to generate the questionnaire." msgstr "" #: ../sdaps/setuptex/__init__.py:122 msgid "Caught an Exception while parsing the SDAPS file. The current state is:" msgstr "" #: ../sdaps/setuptex/__init__.py:136 msgid "" "Some combination of options and project properties do not work. Aborted " "Setup." msgstr "" #: ../sdaps/setuptex/__init__.py:162 msgid "" "An error occured in the setup routine. The survey directory still exists. " "You can for example check the questionnaire.log file for LaTeX compile " "errors." msgstr "" #: ../sdaps/reporttex/__init__.py:107 msgid "author|Unknown" msgstr "" #: ../sdaps/reporttex/__init__.py:138 msgid "tex language|english" msgstr "" #: ../sdaps/reporttex/__init__.py:155 #, python-format msgid "The TeX project with the report data is located at '%s'." msgstr "" #: ../sdaps/reporttex/__init__.py:158 #, python-format msgid "Running %s now twice to generate the report." msgstr "" #: ../sdaps/reporttex/__init__.py:168 #, python-format msgid "An occured during creation of the report. Temporary files left in '%s'." msgstr "" sdaps-1.9.8/po/pl.po0000644000175000000660000006071213410742232014774 0ustar benjaminlock00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: SDAPS 0.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:10+0100\n" "PO-Revision-Date: 2018-04-10 15:00+0200\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " "|| n%100>=20) ? 1 : 2);\n" #: ../sdaps/script.py:41 msgid "SDAPS -- Paper based survey tool." msgstr "" #: ../sdaps/script.py:45 msgid "command list|Commands:" msgstr "" #: ../sdaps/script.py:50 msgid "project directory|The SDAPS project." msgstr "" #: ../sdaps/add/__init__.py:55 #, python-format msgid "" "Invalid input file %s. You need to specify a (multipage) monochrome TIFF as " "input." msgstr "" #: ../sdaps/add/__init__.py:67 #, python-format msgid "" "Not adding %s because it has a wrong page count (needs to be a mulitple of " "%i)." msgstr "" #: ../sdaps/boxgallery/__init__.py:108 #, python-format msgid "Rendering boxgallery for metric \"%s\"." msgstr "" #: ../sdaps/log.py:37 msgid "Warning: " msgstr "" #: ../sdaps/log.py:41 msgid "Error: " msgstr "" #: ../sdaps/cmdline/add.py:31 msgid "Add scanned questionnaires to the survey." msgstr "" #: ../sdaps/cmdline/add.py:32 msgid "" "This command is used to add scanned images to the survey.\n" " The image data needs to be a (multipage) 300dpi monochrome TIFF file. " "You\n" " may choose not to copy the data into the project directory. In that " "case\n" " the data will be referenced using a relative path." msgstr "" #: ../sdaps/cmdline/add.py:38 msgid "Convert given files and add the result." msgstr "" #: ../sdaps/cmdline/add.py:43 msgid "" "Do a 3D-transformation after finding the corner marks. If the\n" " corner marks are not found then the image will be added as-is." msgstr "" #: ../sdaps/cmdline/add.py:49 msgid "" "Force adding the images even if the page count is wrong (only use if you " "know what you are doing)." msgstr "" #: ../sdaps/cmdline/add.py:53 msgid "Copy the files into the directory (default)." msgstr "" #: ../sdaps/cmdline/add.py:58 msgid "Do not copy the files into the directory." msgstr "" #: ../sdaps/cmdline/add.py:62 msgid "" "Images contain a duplex scan of a simplex questionnaire (default: simplex " "scan)." msgstr "" #: ../sdaps/cmdline/add.py:68 ../sdaps/cmdline/convert.py:48 msgid "A number of TIFF image files." msgstr "" #: ../sdaps/cmdline/add.py:94 msgid "The --no-copy option is not compatible with --convert!" msgstr "" #: ../sdaps/cmdline/add.py:103 msgid "Converting input files into a single temporary file." msgstr "" #: ../sdaps/cmdline/add.py:115 msgid "" "The page count of the created temporary file does not work with this survey." msgstr "" #: ../sdaps/cmdline/add.py:120 msgid "Running the conversion failed." msgstr "" #: ../sdaps/cmdline/add.py:126 #, python-format msgid "Processing %s" msgstr "" #: ../sdaps/cmdline/add.py:130 ../sdaps/reset/__init__.py:33 msgid "Done" msgstr "" #: ../sdaps/cmdline/annotate.py:28 msgid "Annotate the questionnaire and show the recognized positions." msgstr "" #: ../sdaps/cmdline/annotate.py:29 msgid "" "This command is mainly a debug utility. It creates an\n" " annotated version of the questionnaire, with the information that SDAPS\n" " knows about it overlayed on top." msgstr "" #: ../sdaps/cmdline/boxgallery.py:31 msgid "Create PDFs with boxes sorted by the detection heuristics." msgstr "" #: ../sdaps/cmdline/boxgallery.py:32 msgid "" "SDAPS uses multiple heuristics to detect determine the\n" " state of checkboxes. There is a list for each heuristic giving the " "expected\n" " state and the quality of the value (see defs.py). Using this command a " "PDF\n" " will be created for each of the heuristics so that one can adjust the\n" " values." msgstr "" #: ../sdaps/cmdline/boxgallery.py:40 msgid "" "Reruns part of the recognition process and retrieves debug images from this " "step." msgstr "" #: ../sdaps/cmdline/convert.py:30 msgid "Convert a set of images to the correct image format." msgstr "" #: ../sdaps/cmdline/convert.py:31 msgid "" "This command can be used if you scanned files in something\n" " other than the expected monochrome TIFF mode. All given files will\n" " be loaded, converted to monochrome and stored in a multipage 1bpp\n" " TIFF file. Optionally, you can select \"3D transformation\"\\ ,which " "may facilitate\n" " working with photos of questionnaires instead of scans." msgstr "" #: ../sdaps/cmdline/convert.py:38 msgid "" "Do a 3D-transformation after finding the corner marks.\n" " If they are not found, the image will be processed as-is." msgstr "" #: ../sdaps/cmdline/convert.py:44 msgid "The location of the output file." msgstr "" #: ../sdaps/cmdline/convert.py:57 msgid "No output filename specified!" msgstr "" #: ../sdaps/cmdline/cover.py:27 msgid "Create a cover for the questionnaires." msgstr "" #: ../sdaps/cmdline/cover.py:28 msgid "" "This command creates a cover page for questionnaires. All\n" " the metadata of the survey will be printed on the page." msgstr "" #: ../sdaps/cmdline/cover.py:31 #, python-format msgid "Filename to store the data to (default: cover_%%i.pdf)" msgstr "" #: ../sdaps/cmdline/csvdata.py:34 msgid "Import or export data to/from CSV files." msgstr "" #: ../sdaps/cmdline/csvdata.py:35 msgid "" "Import or export data to/from a CSV file. The first line\n" " is a header which defines questionnaire_id and global_id, and a column\n" " for each checkbox and textfield. Note that the import is currently very\n" " limited, as you need to specifiy the questionnaire ID to select the " "sheet\n" " which should be updated." msgstr "" #: ../sdaps/cmdline/csvdata.py:44 msgid "Export data to CSV file." msgstr "" #: ../sdaps/cmdline/csvdata.py:46 #, python-format msgid "Filename to store the data to (default: data_%%i.csv)" msgstr "" #: ../sdaps/cmdline/csvdata.py:48 msgid "The delimiter used in the CSV file (default ',')" msgstr "" #: ../sdaps/cmdline/csvdata.py:52 ../sdaps/cmdline/report.py:31 #: ../sdaps/cmdline/reporttex.py:52 msgid "Filter to only export a partial dataset." msgstr "" #: ../sdaps/cmdline/csvdata.py:54 msgid "Export images of freeform fields." msgstr "" #: ../sdaps/cmdline/csvdata.py:60 msgid "Export an image for each question that includes all boxes." msgstr "" #: ../sdaps/cmdline/csvdata.py:66 msgid "Export the recognition quality for each checkbox." msgstr "" #: ../sdaps/cmdline/csvdata.py:74 msgid "Import data to from a CSV file." msgstr "" #: ../sdaps/cmdline/csvdata.py:76 msgid "The file to import." msgstr "" #: ../sdaps/cmdline/gui.py:28 msgid "Launch a GUI. You can view and alter the (recognized) answers with it." msgstr "" #: ../sdaps/cmdline/gui.py:29 msgid "" "This command launches a graphical user interface that can\n" " be used to correct answers. You need to run \"recognize\" before using " "it.\n" " " msgstr "" #: ../sdaps/cmdline/gui.py:34 msgid "Filter to only show a partial dataset." msgstr "" #: ../sdaps/cmdline/ids.py:29 msgid "Export and import questionnaire IDs." msgstr "" #: ../sdaps/cmdline/ids.py:30 msgid "" "This command can be used to import and export questionnaire\n" " IDs. It only makes sense in projects where such an ID is printed on the\n" " questionnaire. Note that you can also add IDs by using the stamp " "command,\n" " which will give you the PDF at the same time." msgstr "" #: ../sdaps/cmdline/ids.py:35 #, python-format msgid "Filename to store the data to (default: ids_%%i)" msgstr "" #: ../sdaps/cmdline/ids.py:38 msgid "Add IDs to the internal list from the specified file." msgstr "" #: ../sdaps/cmdline/info.py:28 msgid "Display and modify metadata of project." msgstr "" #: ../sdaps/cmdline/info.py:29 msgid "" "This command lets you modify the metadata of the SDAPS\n" " project. You can modify, add and remove arbitrary keys that will be " "printed\n" " on the report. The only key that always exist is \"title\".\n" " If no key is given then a list of defined keys is printed." msgstr "" #: ../sdaps/cmdline/info.py:36 msgid "Delete the key and value pair." msgstr "" #: ../sdaps/cmdline/info.py:40 msgid "The key to display or modify." msgstr "" #: ../sdaps/cmdline/info.py:44 msgid "Set the given key to this value." msgstr "" #: ../sdaps/cmdline/info.py:69 msgid "Existing fields:\n" msgstr "" #: ../sdaps/cmdline/recognize.py:28 msgid "Run the optical mark recognition." msgstr "" #: ../sdaps/cmdline/recognize.py:29 msgid "" "Iterates over all images and runs the optical mark\n" " recognition. It will reevaluate sheets even if \"recognize\" has " "already\n" " run or manual changes were made." msgstr "" #: ../sdaps/cmdline/recognize.py:34 msgid "" "Only identify the page properties, but don't recognize the checkbox states." msgstr "" #: ../sdaps/cmdline/recognize.py:39 msgid "" "Rerun the recognition for all pages. The default is to skip all pages that " "were recognized or verified already." msgstr "" #: ../sdaps/cmdline/reorder.py:26 msgid "Reorder pages according to questionnaire ID." msgstr "" #: ../sdaps/cmdline/reorder.py:27 msgid "" "This command reorders all pages according to the already\n" " recognized questionnaire ID. To use it add all the files to the " "project,\n" " then run a partial recognition using \"recognize --identify\". After " "this\n" " you have to run this command to reorder the data for the real " "recognition.\n" " " msgstr "" #: ../sdaps/cmdline/report.py:26 msgid "Create a PDF report." msgstr "" #: ../sdaps/cmdline/report.py:27 msgid "" "This command creates a PDF report using reportlab that\n" " contains statistics and if selected the freeform fields." msgstr "" #: ../sdaps/cmdline/report.py:33 msgid "Create a filtered report for every checkbox." msgstr "" #: ../sdaps/cmdline/report.py:36 msgid "Short format (without freeform text fields)." msgstr "" #: ../sdaps/cmdline/report.py:41 msgid "Detailed output. (default)" msgstr "" #: ../sdaps/cmdline/report.py:47 ../sdaps/cmdline/reporttex.py:30 msgid "" "Do not include original images in the report. This is useful if there are " "privacy concerns." msgstr "" #: ../sdaps/cmdline/report.py:52 ../sdaps/cmdline/reporttex.py:35 msgid "Do not use substitutions instead of images." msgstr "" #: ../sdaps/cmdline/report.py:58 ../sdaps/cmdline/reporttex.py:46 msgid "The paper size used for the output (default: locale dependent)" msgstr "" #: ../sdaps/cmdline/report.py:61 ../sdaps/cmdline/reporttex.py:49 #, python-format msgid "Filename to store the data to (default: report_%%i.pdf)" msgstr "" #: ../sdaps/cmdline/reporttex.py:26 msgid "Create a PDF report using LaTeX." msgstr "" #: ../sdaps/cmdline/reporttex.py:27 msgid "" "This command creates a PDF report using LaTeX that\n" " contains statistics and freeform fields." msgstr "" #: ../sdaps/cmdline/reporttex.py:41 msgid "Save the generated TeX files instead of the final PDF." msgstr "" #: ../sdaps/cmdline/reset.py:26 msgid "Reset project into original state" msgstr "" #: ../sdaps/cmdline/reset.py:27 msgid "" "This command does a full reset of the project. All data\n" " will be discarded and only the empty project is left.\n" " " msgstr "" #: ../sdaps/cmdline/setup.py:27 msgid "Create a new survey using a LaTeX document." msgstr "" #: ../sdaps/cmdline/setup.py:28 msgid "" "Create a new survey from a LaTeX document. You need to\n" " be using the SDAPS class. All the metadata and options for the project\n" " can be set inside the LaTeX document." msgstr "" #: ../sdaps/cmdline/setup.py:33 msgid "The LaTeX Document" msgstr "" #: ../sdaps/cmdline/setup.py:35 msgid "" "Additional files that are required by the LaTeX document and need to be " "copied into the project directory." msgstr "" #: ../sdaps/cmdline/setup.py:39 msgid "Additional questions that are not part of the questionnaire." msgstr "" #: ../sdaps/cmdline/stamp.py:26 msgid "Add marks for automatic processing." msgstr "" #: ../sdaps/cmdline/stamp.py:27 msgid "" "This command creates the printable document. Depending on\n" " the projects setting you are required to specifiy a source for " "questionnaire\n" " IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:33 msgid "" "If using questionnaire IDs, create N questionnaires with randomized IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:36 msgid "" "If using questionnaire IDs, create questionnaires from the IDs read from the " "specified file." msgstr "" #: ../sdaps/cmdline/stamp.py:39 msgid "If using questionnaire IDs, create questionnaires for all stored IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:42 #, python-format msgid "Filename to store the data to (default: stamp_%%i.pdf)" msgstr "" #: ../sdaps/convert/__init__.py:37 #, python-format msgid "Could not apply 3D-transformation to image '%s', page %i!" msgstr "" #: ../sdaps/cover/__init__.py:40 msgid "SDAPS questionnaire" msgstr "" #: ../sdaps/csvdata/buddies.py:77 #, python-format msgid "Not importing unknown questionnaire ID \"%s\"" msgstr "" #: ../sdaps/gui/__init__.py:59 msgid "" "The survey does not have any images! Please add images (and run recognize) " "before using the GUI." msgstr "" #: ../sdaps/gui/__init__.py:211 msgid "Page|Invalid" msgstr "" #: ../sdaps/gui/__init__.py:214 #, python-format msgid "Page %i" msgid_plural "Page %i" msgstr[0] "" msgstr[1] "" #: ../sdaps/gui/__init__.py:256 msgid "Copyright © 2007-2014 The SDAPS Authors" msgstr "" #: ../sdaps/gui/__init__.py:258 msgid "Scripts for data acquisition with paper based surveys" msgstr "" #: ../sdaps/gui/__init__.py:259 msgid "http://sdaps.org" msgstr "" #: ../sdaps/gui/__init__.py:260 msgid "translator-credits" msgstr "" #: ../sdaps/gui/__init__.py:305 #, python-format msgid " of %i" msgstr "" #: ../sdaps/gui/__init__.py:306 #, python-format msgid "Recognition Quality: %.2f" msgstr "" #: ../sdaps/gui/__init__.py:322 msgid "" "You have reached the first page of the survey. Would you like to go to the " "last page?" msgstr "" #: ../sdaps/gui/__init__.py:324 msgid "Go to last page" msgstr "" #: ../sdaps/gui/__init__.py:346 msgid "" "You have reached the last page of the survey. Would you like to go to the " "first page?" msgstr "" #: ../sdaps/gui/__init__.py:348 msgid "Go to first page" msgstr "" #: ../sdaps/gui/__init__.py:457 msgid "Close without saving" msgstr "" #: ../sdaps/gui/__init__.py:461 msgid "" "Save the project before closing?\n" "\n" "If you do not save you may loose data." msgstr "" #: ../sdaps/gui/main_window.ui.h:1 msgid "Forward" msgstr "" #: ../sdaps/gui/main_window.ui.h:2 msgid "Previous" msgstr "" #: ../sdaps/gui/main_window.ui.h:3 msgid "Zoom In" msgstr "" #: ../sdaps/gui/main_window.ui.h:4 msgid "Zoom Out" msgstr "" #: ../sdaps/gui/main_window.ui.h:5 msgid "SDAPS" msgstr "" #: ../sdaps/gui/main_window.ui.h:6 msgid "_File" msgstr "" #: ../sdaps/gui/main_window.ui.h:7 msgid "_View" msgstr "" #: ../sdaps/gui/main_window.ui.h:8 msgid "_Help" msgstr "" #: ../sdaps/gui/main_window.ui.h:9 msgid "Page Rotated" msgstr "" #: ../sdaps/gui/main_window.ui.h:10 msgid "Sort by Quality" msgstr "" #: ../sdaps/gui/main_window.ui.h:11 msgid "label" msgstr "" #: ../sdaps/gui/widget_buddies.py:56 msgid "Global Properties" msgstr "" #: ../sdaps/gui/widget_buddies.py:60 msgid "Sheet valid" msgstr "" #: ../sdaps/gui/widget_buddies.py:61 msgid "Sheet Verified" msgstr "" #: ../sdaps/gui/widget_buddies.py:62 msgid "Page Verified" msgstr "" #: ../sdaps/gui/widget_buddies.py:63 msgid "Empty" msgstr "" #: ../sdaps/gui/widget_buddies.py:75 ../sdaps/gui/widget_buddies.py:105 msgid "Questionnaire ID: " msgstr "" #: ../sdaps/image/__init__.py:47 msgid "" "It appears you have not build the C extension. Please run \"./setup.py build" "\" in the toplevel directory." msgstr "" #: ../sdaps/utils/latex.py:29 msgid "" "The latex character map is missing! Please build it using the supplied tool " "(create-latexmap.py)." msgstr "" #: ../sdaps/utils/latex.py:69 msgid "" "Generated string for LaTeX contains unicode characters. This may not work " "correctly and could mean the LaTeX character map needs to be updated." msgstr "" #: ../sdaps/utils/opencv.py:35 msgid "Cannot convert PDF files as poppler is not installed or usable!" msgstr "" #: ../sdaps/utils/opencv.py:44 msgid "File does not exist" msgstr "" #. The old code used to first filter, and then run; but that is #. a bit ineffective in a way #: ../sdaps/model/survey.py:386 #, python-format msgid "%i sheet" msgid_plural "%i sheets" msgstr[0] "" msgstr[1] "" #: ../sdaps/model/survey.py:402 #, python-format msgid "Processed %i of %i sheets, took %f seconds" msgstr "" #: ../sdaps/model/survey.py:449 msgid "" "A questionnaire that is printed in duplex needs an even amount of pages!" msgstr "" #: ../sdaps/model/survey.py:453 msgid "" "The 'classic' style only supports a maximum of six pages! Use the 'code128' " "style if you require more pages." msgstr "" #: ../sdaps/model/survey.py:466 msgid "IDs need to be integers in \"classic\" style!" msgstr "" #: ../sdaps/model/survey.py:472 #, python-format msgid "Invalid character %s in questionnaire ID \"%s\" in \"code128\" style!" msgstr "" #: ../sdaps/model/survey.py:476 msgid "" "SDAPS cannot draw a questionnaire ID with the \"custom\" style. Do this " "yourself somehow!" msgstr "" #. in simplex mode every page will have a matrix; it might be a None #. matrix though #: ../sdaps/recognize/buddies.py:71 #, python-format msgid "%s, %i: Matrix not recognized." msgstr "" #: ../sdaps/recognize/buddies.py:80 #, python-format msgid "%s, %i: Rotation not found." msgstr "" #. Copy the rotation over (if required) and print warning if the rotation is unknown #: ../sdaps/recognize/buddies.py:84 #, python-format msgid "Neither %s, %i or %s, %i has a known rotation!" msgstr "" #: ../sdaps/recognize/buddies.py:96 #, python-format msgid "%s, %i: Matrix not recognized (again)." msgstr "" #: ../sdaps/recognize/buddies.py:110 #, python-format msgid "%s, %i: Could not get page number." msgstr "" #. Whoa, that should not happen. #: ../sdaps/recognize/buddies.py:130 #, python-format msgid "Neither %s, %i or %s, %i has a known page number!" msgstr "" #. We don't touch the ignore flag in this case #. Simply print a message as this should *never* happen #: ../sdaps/recognize/buddies.py:141 #, python-format msgid "" "Got a simplex document where two adjacent pages had a known page number. " "This should never happen as even simplex scans are converted to duplex by " "inserting dummy pages. Maybe you did a simplex scan but added it in duplex " "mode? The pages in question are %s, %i and %s, %i." msgstr "" #: ../sdaps/recognize/buddies.py:158 #, python-format msgid "Images %s, %i and %s, %i do not have consecutive page numbers!" msgstr "" #: ../sdaps/recognize/buddies.py:174 #, python-format msgid "No page number for page %s, %i exists." msgstr "" #: ../sdaps/recognize/buddies.py:179 #, python-format msgid "Page number for page %s, %i already used by another image." msgstr "" #: ../sdaps/recognize/buddies.py:185 #, python-format msgid "Page number %i for page %s, %i is out of range." msgstr "" #: ../sdaps/recognize/buddies.py:202 #, python-format msgid "%s, %i: Could not read survey ID, but should be able to." msgstr "" #: ../sdaps/recognize/buddies.py:206 #, python-format msgid "Could not read survey ID of either %s, %i or %s, %i!" msgstr "" #. Broken survey ID ... #: ../sdaps/recognize/buddies.py:213 #, python-format msgid "Got a wrong survey ID (%s, %i)! It is %s, but should be %i." msgstr "" #: ../sdaps/recognize/buddies.py:235 #, python-format msgid "%s, %i: Could not read questionnaire ID, but should be able to." msgstr "" #: ../sdaps/recognize/buddies.py:241 #, python-format msgid "Could not read questionnaire ID of either %s, %i or %s, %i!" msgstr "" #: ../sdaps/recognize/buddies.py:271 msgid "" "Got different IDs on different pages for at least one sheet! Do *NOT* try to " "use filters with this survey! You have to run a \"reorder\" step for this to " "work properly!" msgstr "" #: ../sdaps/recognize/buddies.py:326 msgid "No style buddy loaded. This needs to be done for the \"custom\" style!" msgstr "" #: ../sdaps/report/answers.py:188 #, python-format msgid "Answers: %i" msgstr "" #: ../sdaps/report/answers.py:190 #, python-format msgid "Mean: %.2f" msgstr "" #: ../sdaps/report/answers.py:192 #, python-format msgid "Standard Deviation: %.2f" msgstr "" #: ../sdaps/report/__init__.py:75 ../sdaps/reporttex/__init__.py:140 msgid "Turned in Questionnaires" msgstr "" #: ../sdaps/report/__init__.py:92 ../sdaps/reporttex/__init__.py:139 msgid "sdaps report" msgstr "" #: ../sdaps/reset/__init__.py:29 msgid "Removing stored data..." msgstr "" #: ../sdaps/setup/buddies.py:62 #, python-format msgid "Head %(l0)i got no title." msgstr "" #: ../sdaps/setup/buddies.py:74 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no question." msgstr "" #: ../sdaps/setup/buddies.py:114 #, python-format msgid "Error in question \"%s\"" msgstr "" #: ../sdaps/setup/buddies.py:118 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no boxes." msgstr "" #: ../sdaps/setup/buddies.py:167 #, python-format msgid "%(class)s %(l0)i.%(l1)i lower box out of range." msgstr "" #: ../sdaps/setup/buddies.py:172 #, python-format msgid "%(class)s %(l0)i.%(l1)i upper box out of range." msgstr "" #: ../sdaps/setup/buddies.py:177 #, python-format msgid "%(class)s %(l0)i.%(l1)i lower box not before upper box." msgstr "" #: ../sdaps/setup/buddies.py:213 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly two answers." msgstr "" #: ../sdaps/setup/buddies.py:234 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly one box." msgstr "" #: ../sdaps/stamp/__init__.py:38 msgid "" "You may not specify the number of sheets for this survey. All questionnaires " "will be identical as the survey has been configured to not use questionnaire " "IDs for each sheet." msgstr "" #: ../sdaps/stamp/__init__.py:76 msgid "" "This survey has been configured to use questionnaire IDs. Each questionnaire " "will be unique. You need to use on of the options to add new IDs or use the " "existing ones." msgstr "" #: ../sdaps/stamp/latex.py:18 msgid "" "There should be no need to stamp a SDAPS Project that uses LaTeX and does " "not have different questionnaire IDs printed on each sheet.\n" "I am going to do so anyways." msgstr "" #: ../sdaps/stamp/latex.py:26 #, python-format msgid "Running %s now twice to generate the stamped questionnaire." msgstr "" #: ../sdaps/stamp/latex.py:30 ../sdaps/setuptex/__init__.py:107 #: ../sdaps/setuptex/__init__.py:148 ../sdaps/reporttex/__init__.py:162 #, python-format msgid "Error running \"%s\" to compile the LaTeX file." msgstr "" #: ../sdaps/stamp/latex.py:36 #, python-format msgid "" "An error occured during creation of the report. Temporary files left in '%s'." msgstr "" #: ../sdaps/setuptex/__init__.py:46 msgid "The survey directory already exists." msgstr "" #: ../sdaps/setuptex/__init__.py:51 #, python-format msgid "Unknown file type (%s). questionnaire_tex should be of type text/x-tex." msgstr "" #: ../sdaps/setuptex/__init__.py:52 msgid "Will keep going, but expect failure!" msgstr "" #: ../sdaps/setuptex/__init__.py:57 #, python-format msgid "Unknown file type (%s). additionalqobjects should be text/plain." msgstr "" #: ../sdaps/setuptex/__init__.py:103 ../sdaps/setuptex/__init__.py:143 #, python-format msgid "Running %s now twice to generate the questionnaire." msgstr "" #: ../sdaps/setuptex/__init__.py:122 msgid "Caught an Exception while parsing the SDAPS file. The current state is:" msgstr "" #: ../sdaps/setuptex/__init__.py:136 msgid "" "Some combination of options and project properties do not work. Aborted " "Setup." msgstr "" #: ../sdaps/setuptex/__init__.py:162 msgid "" "An error occured in the setup routine. The survey directory still exists. " "You can for example check the questionnaire.log file for LaTeX compile " "errors." msgstr "" #: ../sdaps/reporttex/__init__.py:107 msgid "author|Unknown" msgstr "" #: ../sdaps/reporttex/__init__.py:138 msgid "tex language|english" msgstr "" #: ../sdaps/reporttex/__init__.py:155 #, python-format msgid "The TeX project with the report data is located at '%s'." msgstr "" #: ../sdaps/reporttex/__init__.py:158 #, python-format msgid "Running %s now twice to generate the report." msgstr "" #: ../sdaps/reporttex/__init__.py:168 #, python-format msgid "An occured during creation of the report. Temporary files left in '%s'." msgstr "" sdaps-1.9.8/po/pt.po0000644000175000000660000013023313462531573015013 0ustar benjaminlock00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: SDAPS 0.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:10+0100\n" "PO-Revision-Date: 2019-04-30 00:48+0000\n" "Last-Translator: Rui Mendes \n" "Language-Team: Portuguese \n" "Language: pt\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 3.6.1\n" #: ../sdaps/script.py:41 msgid "SDAPS -- Paper based survey tool." msgstr "SDAPS -- Ferramenta para reconhecimento de questionários em papel." #: ../sdaps/script.py:45 msgid "command list|Commands:" msgstr "lista de comandos|Comandos:" #: ../sdaps/script.py:50 msgid "project directory|The SDAPS project." msgstr "pasta do projeto|Projeto SDAPS." #: ../sdaps/add/__init__.py:55 #, python-format msgid "" "Invalid input file %s. You need to specify a (multipage) monochrome TIFF as " "input." msgstr "" "Ficheiro de entrada inválido %s. Tem de especificar uma imagem TIFF (multi-" "páginas) monocromática como entrada." #: ../sdaps/add/__init__.py:67 #, python-format msgid "" "Not adding %s because it has a wrong page count (needs to be a mulitple of " "%i)." msgstr "" "%s não foi adicionado porque tem um número de páginas errado (tem de ser um " "múltiplo de %i)." #: ../sdaps/boxgallery/__init__.py:108 #, python-format msgid "Rendering boxgallery for metric \"%s\"." msgstr "A renderizar caixas pela métrica \"%s\"." #: ../sdaps/log.py:37 msgid "Warning: " msgstr "Atenção: " #: ../sdaps/log.py:41 msgid "Error: " msgstr "Erro: " #: ../sdaps/cmdline/add.py:31 msgid "Add scanned questionnaires to the survey." msgstr "Adicionar questionários digitalizados na pesquisa." #: ../sdaps/cmdline/add.py:32 msgid "" "This command is used to add scanned images to the survey.\n" " The image data needs to be a (multipage) 300dpi monochrome TIFF file. " "You\n" " may choose not to copy the data into the project directory. In that " "case\n" " the data will be referenced using a relative path." msgstr "" "Este comando é usado para adicionar imagens digitalizadas no questionário.\n" " A imagem tem de ser no formato TIFF (multi-páginas) monocromático a " "300dpi.\n" " Pode optar por não copiar os dados para a pasta do projeto. Nesse\n" " caso os dados serão referenciados usando um caminho relativo." #: ../sdaps/cmdline/add.py:38 msgid "Convert given files and add the result." msgstr "Converter os ficheiros especificados e adicionar o resultado." #: ../sdaps/cmdline/add.py:43 msgid "" "Do a 3D-transformation after finding the corner marks. If the\n" " corner marks are not found then the image will be added as-is." msgstr "" "Faz uma transformação 3D depois de encontrar as marcas de canto.\n" " Se as marcas não forem encontradas, a imagem é adicionada tal como " "está." #: ../sdaps/cmdline/add.py:49 msgid "" "Force adding the images even if the page count is wrong (only use if you " "know what you are doing)." msgstr "" "Força a adição das imagens, mesmo que a contagem de páginas esteja errada (" "use apenas se souber o que está a fazer)." #: ../sdaps/cmdline/add.py:53 msgid "Copy the files into the directory (default)." msgstr "Copiar os ficheiros para a pasta (padrão)." #: ../sdaps/cmdline/add.py:58 msgid "Do not copy the files into the directory." msgstr "Não copiar os ficheiros para a pasta." #: ../sdaps/cmdline/add.py:62 msgid "" "Images contain a duplex scan of a simplex questionnaire (default: simplex " "scan)." msgstr "" "As imagens contêm uma digitalização das 2 faces de cada página (duplex) de " "um questionário só com 1 face de cada página (padrão: digitalização simplex)." #: ../sdaps/cmdline/add.py:68 ../sdaps/cmdline/convert.py:48 msgid "A number of TIFF image files." msgstr "Um número de ficheiros de imagens TIFF." #: ../sdaps/cmdline/add.py:94 msgid "The --no-copy option is not compatible with --convert!" msgstr "A opção --no-copy não é compatível com --convert!" #: ../sdaps/cmdline/add.py:103 msgid "Converting input files into a single temporary file." msgstr "Converter ficheiros de entrada numa pasta temporária." #: ../sdaps/cmdline/add.py:115 msgid "" "The page count of the created temporary file does not work with this survey." msgstr "" "O número de páginas do ficheiro criado temporariamente não funciona com este " "questionário." #: ../sdaps/cmdline/add.py:120 msgid "Running the conversion failed." msgstr "A conversão falhou." #: ../sdaps/cmdline/add.py:126 #, python-format msgid "Processing %s" msgstr "A processar %s" #: ../sdaps/cmdline/add.py:130 ../sdaps/reset/__init__.py:33 msgid "Done" msgstr "Concluído" #: ../sdaps/cmdline/annotate.py:28 msgid "Annotate the questionnaire and show the recognized positions." msgstr "Anotar o questionário e mostrar as posições reconhecidas." #: ../sdaps/cmdline/annotate.py:29 msgid "" "This command is mainly a debug utility. It creates an\n" " annotated version of the questionnaire, with the information that SDAPS\n" " knows about it overlayed on top." msgstr "" "Este comando é principalmente um utilitário de depuração. Ele cria uma\n" " versão anotada do questionário, com as informações que o SDAPS\n" " sabe sobre ele, sobrepostas na parte superior." #: ../sdaps/cmdline/boxgallery.py:31 msgid "Create PDFs with boxes sorted by the detection heuristics." msgstr "Cria PDFs com caixas ordenadas por heurísticas de deteção." #: ../sdaps/cmdline/boxgallery.py:32 msgid "" "SDAPS uses multiple heuristics to detect determine the\n" " state of checkboxes. There is a list for each heuristic giving the " "expected\n" " state and the quality of the value (see defs.py). Using this command a " "PDF\n" " will be created for each of the heuristics so that one can adjust the\n" " values." msgstr "" "O SDAPS usa várias heurísticas para determinar o estado das caixas.\n" " Há uma lista para cada heurística dando o estado esperado e a qualidade\n" " do valor (ver defs.py). Usando este comando, será criado um PDF para " "cada\n" " uma das heurísticas, para que se possa ajustar os valores." #: ../sdaps/cmdline/boxgallery.py:40 msgid "" "Reruns part of the recognition process and retrieves debug images from this " "step." msgstr "" "Executa o reconhecimento novamente e armazena imagens adicionais para " "depuração a partir deste passo." #: ../sdaps/cmdline/convert.py:30 msgid "Convert a set of images to the correct image format." msgstr "Converte um conjunto de imagens para o formato de imagem correto." #: ../sdaps/cmdline/convert.py:31 msgid "" "This command can be used if you scanned files in something\n" " other than the expected monochrome TIFF mode. All given files will\n" " be loaded, converted to monochrome and stored in a multipage 1bpp\n" " TIFF file. Optionally, you can select \"3D transformation\"\\ ,which " "may facilitate\n" " working with photos of questionnaires instead of scans." msgstr "" "Esse comando pode ser usado se tiver ficheiros digitalizados num formato " "diferente\n" "\tdo TIFF monocromático esperado. Todos os ficheiros serão carregados,\n" "\tconvertidos em monocromático e armazenados num ficheiro TIFF multi-página " "de 1bpp.\n" "\tOpcionalmente, pode selecionar Transformação 3D, o que pode facilitar\n" "\to trabalho com fotos dos questionários em vez da digitalização " "convencional." #: ../sdaps/cmdline/convert.py:38 msgid "" "Do a 3D-transformation after finding the corner marks.\n" " If they are not found, the image will be processed as-is." msgstr "" "Faz uma transformação 3D depois de encontrar as marcas de canto.\n" " Se as marcas não forem encontradas, a imagem é adicionada tal como " "está." #: ../sdaps/cmdline/convert.py:44 msgid "The location of the output file." msgstr "A localização do ficheiro de saída." #: ../sdaps/cmdline/convert.py:57 msgid "No output filename specified!" msgstr "Não foi especificado o nome do ficheiro de saída!" #: ../sdaps/cmdline/cover.py:27 msgid "Create a cover for the questionnaires." msgstr "Criar uma página de rosto para os questionários." #: ../sdaps/cmdline/cover.py:28 msgid "" "This command creates a cover page for questionnaires. All\n" " the metadata of the survey will be printed on the page." msgstr "" "Este comando cria uma página de rosto para os questionários.\n" " Todos os metadados do questionário serão impressos nela." #: ../sdaps/cmdline/cover.py:31 #, python-format msgid "Filename to store the data to (default: cover_%%i.pdf)" msgstr "Nome do ficheiro para armazenar os dados (padrão: cover_%%i.pdf)" #: ../sdaps/cmdline/csvdata.py:34 msgid "Import or export data to/from CSV files." msgstr "Importar ou exportar dados de/para ficheiros CSV." #: ../sdaps/cmdline/csvdata.py:35 msgid "" "Import or export data to/from a CSV file. The first line\n" " is a header which defines questionnaire_id and global_id, and a column\n" " for each checkbox and textfield. Note that the import is currently very\n" " limited, as you need to specifiy the questionnaire ID to select the " "sheet\n" " which should be updated." msgstr "" "Importar ou exportar dados de/para um ficheiro CSV. A primeira linha\n" " é um cabeçalho, que define questionnaire_id, global_id e uma coluna\n" " para cada caixa de verificação e campo de texto. Note que a importação " "é\n" " atualmente muito limitada, já que tem de especificar o identificador\n" " do questionário para selecionar a folha que deve ser atualizada." #: ../sdaps/cmdline/csvdata.py:44 msgid "Export data to CSV file." msgstr "Exportar dados para um ficheiro CSV." #: ../sdaps/cmdline/csvdata.py:46 #, python-format msgid "Filename to store the data to (default: data_%%i.csv)" msgstr "Nome do ficheiro para armazenar os dados (padrão: data_%%i.csv)" #: ../sdaps/cmdline/csvdata.py:48 msgid "The delimiter used in the CSV file (default ',')" msgstr "O delimitador usado no ficheiro CSV (padrão ',')" #: ../sdaps/cmdline/csvdata.py:52 ../sdaps/cmdline/report.py:31 #: ../sdaps/cmdline/reporttex.py:52 msgid "Filter to only export a partial dataset." msgstr "Filtro para exportar apenas um conjunto parcial de dados." #: ../sdaps/cmdline/csvdata.py:54 msgid "Export images of freeform fields." msgstr "Exportar imagens dos campos de forma livre." #: ../sdaps/cmdline/csvdata.py:60 msgid "Export an image for each question that includes all boxes." msgstr "Exportar uma imagem para cada pergunta que inclui todas as caixas." #: ../sdaps/cmdline/csvdata.py:66 msgid "Export the recognition quality for each checkbox." msgstr "Exportar a qualidade do reconhecimento para cada caixa de verificação." #: ../sdaps/cmdline/csvdata.py:74 msgid "Import data to from a CSV file." msgstr "Importar dados de um ficheiro CSV." #: ../sdaps/cmdline/csvdata.py:76 msgid "The file to import." msgstr "O ficheiro a ser importado." #: ../sdaps/cmdline/gui.py:28 msgid "Launch a GUI. You can view and alter the (recognized) answers with it." msgstr "" "Abrir uma interface gráfica (GUI). Pode visualizar e alterar as respostas " "(reconhecidas) nela." #: ../sdaps/cmdline/gui.py:29 msgid "" "This command launches a graphical user interface that can\n" " be used to correct answers. You need to run \"recognize\" before using " "it.\n" " " msgstr "" "Este comando lança uma interface gráfica (GUI) que pode ser utilizada para\n" " corrigir respostas. Tem de executar \"recognize\" antes de usá-lo.\n" " " #: ../sdaps/cmdline/gui.py:34 msgid "Filter to only show a partial dataset." msgstr "Filtro para mostrar apenas um conjunto de dados parcial." #: ../sdaps/cmdline/ids.py:29 msgid "Export and import questionnaire IDs." msgstr "Exportação e importação de identificadores (IDs) de questionários." #: ../sdaps/cmdline/ids.py:30 msgid "" "This command can be used to import and export questionnaire\n" " IDs. It only makes sense in projects where such an ID is printed on the\n" " questionnaire. Note that you can also add IDs by using the stamp " "command,\n" " which will give you the PDF at the same time." msgstr "" "Esse comando pode ser usado para importar e exportar IDs de questionários.\n" " Só faz sentido em projetos onde tal identificação é impressa no\n" " questionário. Note que também pode adicionar IDs usando o comando\n" " \"stamp\", que também lhe dará o ficheiro PDF." #: ../sdaps/cmdline/ids.py:35 #, python-format msgid "Filename to store the data to (default: ids_%%i)" msgstr "Nome do ficheiro para armazenar os dados (padrão: ids_%%i)" #: ../sdaps/cmdline/ids.py:38 msgid "Add IDs to the internal list from the specified file." msgstr "Adicionar IDs à lista interna do ficheiro especificado." #: ../sdaps/cmdline/info.py:28 msgid "Display and modify metadata of project." msgstr "Mostrar e alterar os metadados do projeto." #: ../sdaps/cmdline/info.py:29 msgid "" "This command lets you modify the metadata of the SDAPS\n" " project. You can modify, add and remove arbitrary keys that will be " "printed\n" " on the report. The only key that always exist is \"title\".\n" " If no key is given then a list of defined keys is printed." msgstr "" "Este comando permite que altere os metadados do projeto SDAPS.\n" " Pode alterar, adicionar e remover chaves arbitrárias que serão " "impressas\n" " no relatório. A única chave que existe sempre é \"title\".\n" " Se não for fornecida nenhuma chave, é impressa uma lista de chaves." #: ../sdaps/cmdline/info.py:36 msgid "Delete the key and value pair." msgstr "Eliminar o par de chave e valor." #: ../sdaps/cmdline/info.py:40 msgid "The key to display or modify." msgstr "A chave a mostrar ou alterar." #: ../sdaps/cmdline/info.py:44 msgid "Set the given key to this value." msgstr "Defina o chave fornecida para este valor." #: ../sdaps/cmdline/info.py:69 msgid "Existing fields:\n" msgstr "Campos existentes:\n" #: ../sdaps/cmdline/recognize.py:28 msgid "Run the optical mark recognition." msgstr "Executar o reconhecimento ótico de marcas." #: ../sdaps/cmdline/recognize.py:29 msgid "" "Iterates over all images and runs the optical mark\n" " recognition. It will reevaluate sheets even if \"recognize\" has " "already\n" " run or manual changes were made." msgstr "" "Itera sobre todas as imagens e executa o reconhecimento ótico de marcas.\n" " Ele irá reavaliar as folhas mesmo que o comando \"recognize\" tenha " "sido\n" " executado previamente ou tenham sido feitas alterações manuais." #: ../sdaps/cmdline/recognize.py:34 msgid "" "Only identify the page properties, but don't recognize the checkbox states." msgstr "" "Identifica apenas as propriedades da página, mas não reconhece os estados " "das caixas de verificação (respostas)." #: ../sdaps/cmdline/recognize.py:39 msgid "" "Rerun the recognition for all pages. The default is to skip all pages that " "were recognized or verified already." msgstr "" "Executar novamente o reconhecimento para todas as páginas. O padrão é " "ignorar todas as páginas que já foram reconhecidas ou verificadas." #: ../sdaps/cmdline/reorder.py:26 msgid "Reorder pages according to questionnaire ID." msgstr "Reordenar páginas de acordo com o identificador (ID) do questionário." #: ../sdaps/cmdline/reorder.py:27 msgid "" "This command reorders all pages according to the already\n" " recognized questionnaire ID. To use it add all the files to the " "project,\n" " then run a partial recognition using \"recognize --identify\". After " "this\n" " you have to run this command to reorder the data for the real " "recognition.\n" " " msgstr "" "Este comando reordena as páginas pelo ID do questionário já reconhecido\n" " Para usá-lo, adicione todos os ficheiros ao projeto, depois\n" " execute o reconhecimento parcial com \"recognize --identify\".\n" " Após isto, tem de executar este comando para reordenar\n" " os dados para o real reconhecimento.\n" " " #: ../sdaps/cmdline/report.py:26 msgid "Create a PDF report." msgstr "Criar um relatório PDF." #: ../sdaps/cmdline/report.py:27 msgid "" "This command creates a PDF report using reportlab that\n" " contains statistics and if selected the freeform fields." msgstr "" "Este comando cria um relatório em PDF usando o reportlab que\n" " contém estatísticas e os campos de forma livre, se selecionados." #: ../sdaps/cmdline/report.py:33 msgid "Create a filtered report for every checkbox." msgstr "Criar um relatório filtrado para cada caixa." #: ../sdaps/cmdline/report.py:36 msgid "Short format (without freeform text fields)." msgstr "Formato curto (sem campos de texto de forma livre)." #: ../sdaps/cmdline/report.py:41 msgid "Detailed output. (default)" msgstr "Saída detalhada. (padrão)" #: ../sdaps/cmdline/report.py:47 ../sdaps/cmdline/reporttex.py:30 msgid "" "Do not include original images in the report. This is useful if there are " "privacy concerns." msgstr "" "Não incluir imagens originais no relatório. Isto é útil se houver " "preocupação com a privacidade." #: ../sdaps/cmdline/report.py:52 ../sdaps/cmdline/reporttex.py:35 msgid "Do not use substitutions instead of images." msgstr "Não usar substituições em vez de imagens." #: ../sdaps/cmdline/report.py:58 ../sdaps/cmdline/reporttex.py:46 msgid "The paper size used for the output (default: locale dependent)" msgstr "" "O tamanho do papel usado para a saída (padrão: dependente do idioma e país)" #: ../sdaps/cmdline/report.py:61 ../sdaps/cmdline/reporttex.py:49 #, python-format msgid "Filename to store the data to (default: report_%%i.pdf)" msgstr "Nome do ficheiro para armazenar os dados (padrão: report_%%i.pdf)" #: ../sdaps/cmdline/reporttex.py:26 msgid "Create a PDF report using LaTeX." msgstr "Criar um relatório em PDF usando LaTeX." #: ../sdaps/cmdline/reporttex.py:27 msgid "" "This command creates a PDF report using LaTeX that\n" " contains statistics and freeform fields." msgstr "" "Este comando cria um relatório em PDF usando LaTeX que\n" " contém estatísticas e campos de forma livre." #: ../sdaps/cmdline/reporttex.py:41 msgid "Save the generated TeX files instead of the final PDF." msgstr "Guardar os ficheiros TeX gerados em vez do PDF final." #: ../sdaps/cmdline/reset.py:26 msgid "Reset project into original state" msgstr "Repor o projeto no seu estado original" #: ../sdaps/cmdline/reset.py:27 msgid "" "This command does a full reset of the project. All data\n" " will be discarded and only the empty project is left.\n" " " msgstr "" "Este comando limpa todo o projeto. Todos os dados são\n" " descartados e é deixado apenas o projeto em branco.\n" " " #: ../sdaps/cmdline/setup.py:27 msgid "Create a new survey using a LaTeX document." msgstr "Criar um novo questionário através de um documento LaTeX." #: ../sdaps/cmdline/setup.py:28 msgid "" "Create a new survey from a LaTeX document. You need to\n" " be using the SDAPS class. All the metadata and options for the project\n" " can be set inside the LaTeX document." msgstr "" "Criar um novo questionário a partir de um documento LaTeX.\n" " Tem de estar a usar a classe SDAPS. Todos os metadados e opções\n" " para o projeto podem ser definidos no documento LaTeX." #: ../sdaps/cmdline/setup.py:33 msgid "The LaTeX Document" msgstr "O documento LaTeX" #: ../sdaps/cmdline/setup.py:35 msgid "" "Additional files that are required by the LaTeX document and need to be " "copied into the project directory." msgstr "" "São necessários ficheiros adicionais para o documento LaTeX e têm de ser " "copiados para o diretório do projeto." #: ../sdaps/cmdline/setup.py:39 msgid "Additional questions that are not part of the questionnaire." msgstr "Perguntas adicionais que não fazem parte do questionário." #: ../sdaps/cmdline/stamp.py:26 msgid "Add marks for automatic processing." msgstr "Adicionar marcas para processamento automático." #: ../sdaps/cmdline/stamp.py:27 msgid "" "This command creates the printable document. Depending on\n" " the projects setting you are required to specifiy a source for " "questionnaire\n" " IDs." msgstr "" "Este comando cria o documento para impressão. Dependendo das configurações\n" " do projeto, tem de especificar uma fonte para os IDs do questionário." #: ../sdaps/cmdline/stamp.py:33 msgid "" "If using questionnaire IDs, create N questionnaires with randomized IDs." msgstr "" "Se estiver a usar IDs de questionário, cria N questionários com IDs " "aleatórios." #: ../sdaps/cmdline/stamp.py:36 msgid "" "If using questionnaire IDs, create questionnaires from the IDs read from the " "specified file." msgstr "" "Se estiver a usar IDs de questionário, cria questionários com os IDs lidos " "do ficheiro especificado." #: ../sdaps/cmdline/stamp.py:39 msgid "If using questionnaire IDs, create questionnaires for all stored IDs." msgstr "" "Se estiver a usar IDs de questionário, cria questionários para todos os IDs " "armazenados." #: ../sdaps/cmdline/stamp.py:42 #, python-format msgid "Filename to store the data to (default: stamp_%%i.pdf)" msgstr "Nome do ficheiro para armazenar os dados (padrão: stamp_%%i.pdf)" #: ../sdaps/convert/__init__.py:37 #, python-format msgid "Could not apply 3D-transformation to image '%s', page %i!" msgstr "Não foi possível aplicar a transformação 3D na imagem '%s', página %i!" #: ../sdaps/cover/__init__.py:40 msgid "SDAPS questionnaire" msgstr "Questionário SDAPS" #: ../sdaps/csvdata/buddies.py:77 #, python-format msgid "Not importing unknown questionnaire ID \"%s\"" msgstr "" "A não importar Identificadores (IDs) desconhecidos de questionário: \"%s\"" #: ../sdaps/gui/__init__.py:59 msgid "" "The survey does not have any images! Please add images (and run recognize) " "before using the GUI." msgstr "" "O questionário não tem imagens! Por favor, adicione imagens e execute o " "comando \"recognize\" antes de usar a interface gráfica (GUI)." #: ../sdaps/gui/__init__.py:211 msgid "Page|Invalid" msgstr "Página|Inválida" #: ../sdaps/gui/__init__.py:214 #, python-format msgid "Page %i" msgid_plural "Page %i" msgstr[0] "Página %i" msgstr[1] "Página %i" #: ../sdaps/gui/__init__.py:256 msgid "Copyright © 2007-2014 The SDAPS Authors" msgstr "Direitos de autor © 2007-2014 Autores do SDAPS" #: ../sdaps/gui/__init__.py:258 msgid "Scripts for data acquisition with paper based surveys" msgstr "" "SDAPS - Scripts para aquisição de dados de questionários baseados em papel" #: ../sdaps/gui/__init__.py:259 msgid "http://sdaps.org" msgstr "http://sdaps.org" #: ../sdaps/gui/__init__.py:260 msgid "translator-credits" msgstr "Rodrigo Antonio Müller; Rui Mendes" #: ../sdaps/gui/__init__.py:305 #, python-format msgid " of %i" msgstr " de %i" #: ../sdaps/gui/__init__.py:306 #, python-format msgid "Recognition Quality: %.2f" msgstr "Qualidade de reconhecimento: %.2f" #: ../sdaps/gui/__init__.py:322 msgid "" "You have reached the first page of the survey. Would you like to go to the " "last page?" msgstr "" "Atingiu a primeira página do questionário. Quer ir para a última página?" #: ../sdaps/gui/__init__.py:324 msgid "Go to last page" msgstr "Ir para a última página" #: ../sdaps/gui/__init__.py:346 msgid "" "You have reached the last page of the survey. Would you like to go to the " "first page?" msgstr "" "Atingiu a última página do questionário. Quer ir para a primeira página?" #: ../sdaps/gui/__init__.py:348 msgid "Go to first page" msgstr "Ir para a primeira página" #: ../sdaps/gui/__init__.py:457 msgid "Close without saving" msgstr "Fechar sem guardar" #: ../sdaps/gui/__init__.py:461 msgid "" "Save the project before closing?\n" "\n" "If you do not save you may loose data." msgstr "" "Quer guardar o projeto antes de fechar?\n" "\n" "Se não guardar, irá perder os dados." #: ../sdaps/gui/main_window.ui.h:1 msgid "Forward" msgstr "Próximo" #: ../sdaps/gui/main_window.ui.h:2 msgid "Previous" msgstr "Anterior" #: ../sdaps/gui/main_window.ui.h:3 msgid "Zoom In" msgstr "Ampliar" #: ../sdaps/gui/main_window.ui.h:4 msgid "Zoom Out" msgstr "Reduzir" #: ../sdaps/gui/main_window.ui.h:5 msgid "SDAPS" msgstr "SDAPS" #: ../sdaps/gui/main_window.ui.h:6 msgid "_File" msgstr "_Ficheiro" #: ../sdaps/gui/main_window.ui.h:7 msgid "_View" msgstr "_Ver" #: ../sdaps/gui/main_window.ui.h:8 msgid "_Help" msgstr "_Ajuda" #: ../sdaps/gui/main_window.ui.h:9 msgid "Page Rotated" msgstr "Página rodada" #: ../sdaps/gui/main_window.ui.h:10 msgid "Sort by Quality" msgstr "Ordenar pela qualidade" #: ../sdaps/gui/main_window.ui.h:11 msgid "label" msgstr "etiqueta" #: ../sdaps/gui/widget_buddies.py:56 msgid "Global Properties" msgstr "Propriedades globais" #: ../sdaps/gui/widget_buddies.py:60 msgid "Sheet valid" msgstr "Folha válida" #: ../sdaps/gui/widget_buddies.py:61 msgid "Sheet Verified" msgstr "Folha verificada" #: ../sdaps/gui/widget_buddies.py:62 msgid "Page Verified" msgstr "Página verificada" #: ../sdaps/gui/widget_buddies.py:63 msgid "Empty" msgstr "Vazio" #: ../sdaps/gui/widget_buddies.py:75 ../sdaps/gui/widget_buddies.py:105 msgid "Questionnaire ID: " msgstr "ID do questionário: " #: ../sdaps/image/__init__.py:47 msgid "" "It appears you have not build the C extension. Please run \"./setup.py build" "\" in the toplevel directory." msgstr "" "Parece que não compilou a extensão C. Por favor execute o comando \"./" "setup.py build\" no diretório principal." #: ../sdaps/utils/latex.py:29 msgid "" "The latex character map is missing! Please build it using the supplied tool " "(create-latexmap.py)." msgstr "" "Falta o mapa de caracteres latex! Por favor compile-o utilizando a " "ferramenta fornecida (create-latexmap.py)." #: ../sdaps/utils/latex.py:69 msgid "" "Generated string for LaTeX contains unicode characters. This may not work " "correctly and could mean the LaTeX character map needs to be updated." msgstr "" "A expressão gerada para o LaTeX contém caracteres unicode. Isto pode não " "funcionar corretamente e pode significar que o mapa de caracteres LaTeX tem " "de ser atualizado." #: ../sdaps/utils/opencv.py:35 msgid "Cannot convert PDF files as poppler is not installed or usable!" msgstr "" "Não é possível converter ficheiros PDF, pois o poppler não está instalado ou " "não é utilizável!" #: ../sdaps/utils/opencv.py:44 msgid "File does not exist" msgstr "O ficheiro não existe" #. The old code used to first filter, and then run; but that is #. a bit ineffective in a way #: ../sdaps/model/survey.py:386 #, python-format msgid "%i sheet" msgid_plural "%i sheets" msgstr[0] "%i folha" msgstr[1] "%i folhas" #: ../sdaps/model/survey.py:402 #, python-format msgid "Processed %i of %i sheets, took %f seconds" msgstr "Processadas %i de %i folhas, demorou %f segundos" #: ../sdaps/model/survey.py:449 msgid "" "A questionnaire that is printed in duplex needs an even amount of pages!" msgstr "" "Um questionário impresso em dupla face necessita de uma quantidade par de " "páginas!" #: ../sdaps/model/survey.py:453 msgid "" "The 'classic' style only supports a maximum of six pages! Use the 'code128' " "style if you require more pages." msgstr "" "O estilo 'classic' suporta no máximo apenas seis páginas! Use o estilo " "'code128' se precisa de mais páginas." #: ../sdaps/model/survey.py:466 msgid "IDs need to be integers in \"classic\" style!" msgstr "Os IDs têm de ser números inteiros no estilo \"clássico\"!" #: ../sdaps/model/survey.py:472 #, python-format msgid "Invalid character %s in questionnaire ID \"%s\" in \"code128\" style!" msgstr "" "Caractere inválido %s no ID do questionário \"%s\" com estilo \"code128\"!" #: ../sdaps/model/survey.py:476 msgid "" "SDAPS cannot draw a questionnaire ID with the \"custom\" style. Do this " "yourself somehow!" msgstr "" "SDAPS não pode desenhar um ID de questionário com o estilo \"custom\". Faça " "isto de alguma forma!" #. in simplex mode every page will have a matrix; it might be a None #. matrix though #: ../sdaps/recognize/buddies.py:71 #, python-format msgid "%s, %i: Matrix not recognized." msgstr "%s, %i: matriz não reconhecida." #: ../sdaps/recognize/buddies.py:80 #, python-format msgid "%s, %i: Rotation not found." msgstr "%s, %i: rotação não detetada." #. Copy the rotation over (if required) and print warning if the rotation is unknown #: ../sdaps/recognize/buddies.py:84 #, python-format msgid "Neither %s, %i or %s, %i has a known rotation!" msgstr "Nem %s, %i ou %s, %i tem uma rotação conhecida!" #: ../sdaps/recognize/buddies.py:96 #, python-format msgid "%s, %i: Matrix not recognized (again)." msgstr "%s, %i: matriz não reconhecida (novamente)." #: ../sdaps/recognize/buddies.py:110 #, python-format msgid "%s, %i: Could not get page number." msgstr "%s, %i: não foi possível obter o número da página." #. Whoa, that should not happen. #: ../sdaps/recognize/buddies.py:130 #, python-format msgid "Neither %s, %i or %s, %i has a known page number!" msgstr "Nem %s, %i ou %s, %i tem um número de página conhecido!" #. We don't touch the ignore flag in this case #. Simply print a message as this should *never* happen #: ../sdaps/recognize/buddies.py:141 #, python-format msgid "" "Got a simplex document where two adjacent pages had a known page number. " "This should never happen as even simplex scans are converted to duplex by " "inserting dummy pages. Maybe you did a simplex scan but added it in duplex " "mode? The pages in question are %s, %i and %s, %i." msgstr "" "Tenho um documento em folhas de uma face (simplex), onde duas páginas " "adjacentes tem um número de página conhecido. Isto nunca devia acontecer, " "pois mesmo as digitalizações de uma face são convertidas para folhas de " "dupla face, com a inserção de páginas vazias. Será que fez uma digitalização " "de folha de uma face, mas a adicionou em modo de dupla face? As páginas em " "questão são %s, %i e %s, %i." #: ../sdaps/recognize/buddies.py:158 #, python-format msgid "Images %s, %i and %s, %i do not have consecutive page numbers!" msgstr "As imagens %s, %i e %s, %i não tem números de página consecutivos!" #: ../sdaps/recognize/buddies.py:174 #, python-format msgid "No page number for page %s, %i exists." msgstr "Não existe número de página para a página %s, %i." #: ../sdaps/recognize/buddies.py:179 #, python-format msgid "Page number for page %s, %i already used by another image." msgstr "" "O número de página para a página %s, %i já é utilizado por outra imagem." #: ../sdaps/recognize/buddies.py:185 #, python-format msgid "Page number %i for page %s, %i is out of range." msgstr "O número de página %i para a página %s, %i está fora do intervalo." #: ../sdaps/recognize/buddies.py:202 #, python-format msgid "%s, %i: Could not read survey ID, but should be able to." msgstr "" "%s, %i: não foi possível ler o identificador (ID) do questionário, mas devia " "ser possível fazê-lo." #: ../sdaps/recognize/buddies.py:206 #, python-format msgid "Could not read survey ID of either %s, %i or %s, %i!" msgstr "" "Não foi possível ler o identificador (ID) do questionário %s, %i ou %s, %i!" #. Broken survey ID ... #: ../sdaps/recognize/buddies.py:213 #, python-format msgid "Got a wrong survey ID (%s, %i)! It is %s, but should be %i." msgstr "" "Tem um identificador (ID) errado do questionário (%s, %i)! É %s, mas devia " "ser %i." #: ../sdaps/recognize/buddies.py:235 #, python-format msgid "%s, %i: Could not read questionnaire ID, but should be able to." msgstr "" "%s, %i: não foi possível ler o identificador (ID) do questionário, mas devia " "ser possível fazê-lo." #: ../sdaps/recognize/buddies.py:241 #, python-format msgid "Could not read questionnaire ID of either %s, %i or %s, %i!" msgstr "" "Não foi possível ler o identificador (ID) do questionário %s, %i ou %s, %i!" #: ../sdaps/recognize/buddies.py:271 msgid "" "Got different IDs on different pages for at least one sheet! Do *NOT* try to " "use filters with this survey! You have to run a \"reorder\" step for this to " "work properly!" msgstr "" "Tem identificadores (IDs) diferentes em páginas diferentes para pelo menos " "uma folha! *NÃO* tente usar filtros com este questionário! Tem de executar o " "passo \"reorder\" para que isso funcione corretamente!" #: ../sdaps/recognize/buddies.py:326 msgid "No style buddy loaded. This needs to be done for the \"custom\" style!" msgstr "" "Não foram carregadas definições de estilos. Isto tem de ser feito para o " "estilo \"custom\"!" #: ../sdaps/report/answers.py:188 #, python-format msgid "Answers: %i" msgstr "Respostas: %i" #: ../sdaps/report/answers.py:190 #, python-format msgid "Mean: %.2f" msgstr "Média: %.2f" #: ../sdaps/report/answers.py:192 #, python-format msgid "Standard Deviation: %.2f" msgstr "Desvio padrão: %.2f" #: ../sdaps/report/__init__.py:75 ../sdaps/reporttex/__init__.py:140 msgid "Turned in Questionnaires" msgstr "Quantidade de questionários" #: ../sdaps/report/__init__.py:92 ../sdaps/reporttex/__init__.py:139 msgid "sdaps report" msgstr "Relatório SDAPS" #: ../sdaps/reset/__init__.py:29 msgid "Removing stored data..." msgstr "A remover dados armazenados..." #: ../sdaps/setup/buddies.py:62 #, python-format msgid "Head %(l0)i got no title." msgstr "O cabeçalho %(l0)i não tem título." #: ../sdaps/setup/buddies.py:74 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no question." msgstr "%(class)s %(l0)i.%(l1)i não tem perguntas." #: ../sdaps/setup/buddies.py:114 #, python-format msgid "Error in question \"%s\"" msgstr "Erro na pergunta \"%s\"" #: ../sdaps/setup/buddies.py:118 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no boxes." msgstr "%(class)s %(l0)i.%(l1)i não tem caixas." #: ../sdaps/setup/buddies.py:167 #, python-format msgid "%(class)s %(l0)i.%(l1)i lower box out of range." msgstr "%(class)s %(l0)i.%(l1)i caixa baixa fora do intervalo." #: ../sdaps/setup/buddies.py:172 #, python-format msgid "%(class)s %(l0)i.%(l1)i upper box out of range." msgstr "%(class)s %(l0)i.%(l1)i caixa alta fora do intervalo." #: ../sdaps/setup/buddies.py:177 #, python-format msgid "%(class)s %(l0)i.%(l1)i lower box not before upper box." msgstr "%(class)s %(l0)i.%(l1)i caixa baixa não está antes da caixa alta." #: ../sdaps/setup/buddies.py:213 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly two answers." msgstr "%(class)s %(l0)i.%(l1)i não tem exatamente duas respostas." #: ../sdaps/setup/buddies.py:234 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly one box." msgstr "%(class)s %(l0)i.%(l1)i não tem exatamente uma caixa." #: ../sdaps/stamp/__init__.py:38 msgid "" "You may not specify the number of sheets for this survey. All questionnaires " "will be identical as the survey has been configured to not use questionnaire " "IDs for each sheet." msgstr "" "Não pode especificar o número de folhas para este questionário. Todos os " "questionários serão idênticos já que o questionário foi configurado para não " "usar identificadores (IDs) de questionário em cada folha." #: ../sdaps/stamp/__init__.py:76 msgid "" "This survey has been configured to use questionnaire IDs. Each questionnaire " "will be unique. You need to use on of the options to add new IDs or use the " "existing ones." msgstr "" "Este questionário foi configurado para usar identificadores (IDs) de " "questionários. Cada questionário será único. Por isso, deve ser usada uma " "das opções, para adicionar novos IDs ou usar os existentes." #: ../sdaps/stamp/latex.py:18 msgid "" "There should be no need to stamp a SDAPS Project that uses LaTeX and does " "not have different questionnaire IDs printed on each sheet.\n" "I am going to do so anyways." msgstr "" "Não devia ser necessário estampar um projeto SDAPS que usa LaTeX e não tem " "diferentes IDs de questionário impresso em cada folha.\n" "Vou fazê-lo de qualquer maneira." #: ../sdaps/stamp/latex.py:26 #, python-format msgid "Running %s now twice to generate the stamped questionnaire." msgstr "A executar %s duas vezes para gerar o questionário estampado." #: ../sdaps/stamp/latex.py:30 ../sdaps/setuptex/__init__.py:107 #: ../sdaps/setuptex/__init__.py:148 ../sdaps/reporttex/__init__.py:162 #, python-format msgid "Error running \"%s\" to compile the LaTeX file." msgstr "Erro ao executar \"%s\" para compilar o ficheiro LaTeX." #: ../sdaps/stamp/latex.py:36 #, python-format msgid "" "An error occured during creation of the report. Temporary files left in '%s'." msgstr "" "Ocorreu um erro durante a criação do relatório. Os ficheiros temporários " "foram deixados em '%s'." #: ../sdaps/setuptex/__init__.py:46 msgid "The survey directory already exists." msgstr "Já existe o diretório do questionário." #: ../sdaps/setuptex/__init__.py:51 #, python-format msgid "Unknown file type (%s). questionnaire_tex should be of type text/x-tex." msgstr "" "Tipo de ficheiro desconhecido (%s). O questionnaire_tex deve ser do tipo " "text/x-tex." #: ../sdaps/setuptex/__init__.py:52 msgid "Will keep going, but expect failure!" msgstr "Vai continuar, mas espere encontrar falhas!" #: ../sdaps/setuptex/__init__.py:57 #, python-format msgid "Unknown file type (%s). additionalqobjects should be text/plain." msgstr "" "Tipo de ficheiro desconhecido (%s). O additionalqobjects deve ser do tipo " "text/plain." #: ../sdaps/setuptex/__init__.py:103 ../sdaps/setuptex/__init__.py:143 #, python-format msgid "Running %s now twice to generate the questionnaire." msgstr "A executar %s duas vezes para gerar o questionário." #: ../sdaps/setuptex/__init__.py:122 msgid "Caught an Exception while parsing the SDAPS file. The current state is:" msgstr "Houve uma exceção ao processar o ficheiro SDAPS. O estado atual é:" #: ../sdaps/setuptex/__init__.py:136 msgid "" "Some combination of options and project properties do not work. Aborted " "Setup." msgstr "" "Algumas combinações de opções e propriedades do projeto não funcionam. " "Instalação abortada." #: ../sdaps/setuptex/__init__.py:162 msgid "" "An error occured in the setup routine. The survey directory still exists. " "You can for example check the questionnaire.log file for LaTeX compile " "errors." msgstr "" "Ocorreu um erro na rotina de instalação. O diretório do questionário ainda " "existe. Pode ver o ficheiro questionnaire.log para verificar se existem " "erros de compilação do LaTeX." #: ../sdaps/reporttex/__init__.py:107 msgid "author|Unknown" msgstr "autor|Desconhecido" #: ../sdaps/reporttex/__init__.py:138 msgid "tex language|english" msgstr "idioma do texto|português" #: ../sdaps/reporttex/__init__.py:155 #, python-format msgid "The TeX project with the report data is located at '%s'." msgstr "O projeto TeX com os dados do relatório está localizado em '%s'." #: ../sdaps/reporttex/__init__.py:158 #, python-format msgid "Running %s now twice to generate the report." msgstr "A executar %s duas vezes para gerar o relatório." #: ../sdaps/reporttex/__init__.py:168 #, python-format msgid "An occured during creation of the report. Temporary files left in '%s'." msgstr "" "Ocorreu um erro durante a criação do relatório. Os ficheiros temporários " "foram deixados em '%s'." #~ msgid "%f seconds per sheet" #~ msgstr "%f segundos por folha" #~ msgid "Running upgrade routines for file format version %i" #~ msgstr "" #~ "Executando rotinas de atualização para a versão de formato de ficheiro %i" #~ msgid "Create a new survey using an ODT document." #~ msgstr "Criar uma nova pesquisa usando um documento ODT." #~ msgid "" #~ "Create a new surevey from an ODT document. The PDF export\n" #~ " of the file needs to be specified at the same time. SDAPS will " #~ "import\n" #~ " metadata (properties) and the title from the ODT document." #~ msgstr "" #~ "Cria uma nova pesquisa de um documento ODT. O arquivo exportado em PDF\n" #~ " precisa ser especificado ao mesmo tempo. O SDAPS importará os\n" #~ " metadados (propriedades) e o título do documento ODT." #~ msgid "The ODT Document" #~ msgstr "O documento ODT" #~ msgid "PDF export of the ODT document" #~ msgstr "Arquivo PDF exportado a partir do documento ODT" #~ msgid "Enable printing of the survey ID (default)." #~ msgstr "Ativar a impressão do ID da pesquisa (padrão)." #~ msgid "Disable printing of the survey ID." #~ msgstr "Desativar a impressão do ID da pesquisa." #~ msgid "Enable printing of the questionnaire ID." #~ msgstr "Ativar a impressão do ID do questionário." #~ msgid "Disable printing of the questionnaire ID (default)." #~ msgstr "Desativar a impressão do ID do questionário (padrão)." #~ msgid "" #~ "Set an additional global ID for tracking. This can can only be used in " #~ "the \"code128\" style." #~ msgstr "" #~ "Definir um ID Global adicional para monitoramento. Isto só pode ser " #~ "utilizado no estilo \"code128\"." #~ msgid "" #~ "The stamping style to use. Should be either \"classic\" or \"code128\". " #~ "Use \"code128\" for more features." #~ msgstr "" #~ "O estilo que é usado para estampar. Deve ser \"classic\" ou \"code128\". " #~ "Use \"code128\" para mais recursos." #~ msgid "" #~ "Use duplex mode (ie. only print the IDs on the back side). Requires a " #~ "mulitple of two pages." #~ msgstr "" #~ "Use o modo duplex (ou seja, só imprimir as identificações na parte de " #~ "trás). Requer um múltiplo de duas páginas." #~ msgid "" #~ "Use simplex mode. IDs are printed on each page. You need a simplex scan " #~ "currently!" #~ msgstr "" #~ "Use o modo simplex. IDs são impressos em cada página. Você precisa de uma " #~ "verificação simplex atualmente!" #~ msgid "" #~ "Unknown file type (%s). questionnaire_odt should be application/vnd.oasis." #~ "opendocument.text." #~ msgstr "" #~ "Tipo de arquivo desconhecido (%s). O questionnaire_odt deve ser do tipo " #~ "application/vnd.oasis.opendocument.text." #~ msgid "Unknown file type (%s). questionnaire_pdf should be application/pdf." #~ msgstr "" #~ "Tipo de arquivo desconhecido (%s). O questionnaire_pdf deve ser do tipo " #~ "application/pdf." #~ msgid "" #~ "Caught an Exception while parsing the ODT file. The current state is:" #~ msgstr "Houve uma exceção ao analisar o arquivo ODT. O estado atual é:" #~ msgid "" #~ "If the dependencies for the \"annotate\" command are installed, then an " #~ "annotated version will be created next to the original PDF file." #~ msgstr "" #~ "Se as dependências para o comando \"annotate\" estão instaladas, uma " #~ "versão anotada será criada junto ao arquivo PDF original." #~ msgid "" #~ "Warning: Ignoring a box (page: %i, x: %.1f, y: %.1f, width: %.1f, height: " #~ "%.1f)." #~ msgstr "" #~ "Aviso: Ignorando uma caixa (página: %i, x: %.1f, y: %.1f, largura: %.1f, " #~ "altura: %.1f)." #~ msgid "Survey-ID: %i" #~ msgstr "ID da Pesquisa: %i" #~ msgid "Questionnaire-ID: %i" #~ msgstr "ID do Questionário: %i" #, fuzzy #~ msgid "You need to have either PDFtk or pyPdf installed. PDFtk is faster." #~ msgstr "" #~ "Você precisa ter o pdftk ou o pyPdf instalado. pdftk é o método mais " #~ "rápido." #~ msgid "Creating stamp PDF for %i sheet" #~ msgid_plural "Creating stamp PDF for %i sheets" #~ msgstr[0] "Criando estampa PDF para %i folha" #~ msgstr[1] "Criando estampa PDF para %i folhas" #~ msgid "%i sheet; %f seconds per sheet" #~ msgid_plural "%i sheet; %f seconds per sheet" #~ msgstr[0] "%i folha; %f segundos por folha" #~ msgstr[1] "%i folhas; %f segundos por folha" #, fuzzy #~ msgid "Marking using PDFtk" #~ msgstr "Estampando com pdftk" #, fuzzy #~ msgid "PDFtk: Overlaying the original PDF with the markings." #~ msgstr "pdftk: Sobrepondo o PDF original com as marcas." #, fuzzy #~ msgid "PDFtk: Splitting out page %d of each stack." #~ msgid_plural "PDFtk: Splitting out page %d of each stack." #~ msgstr[0] "pdftk: Extraindo a página %d de cada folha." #~ msgstr[1] "pdftk: Extraindo a página %d de cada folha." #, fuzzy #~ msgid "PDFtk: Splitting the questionnaire for marking." #~ msgstr "pdftk: Dividindo o questionário para marca d'água." #, fuzzy #~ msgid "PDFtk: Marking page %d of all stacks." #~ msgid_plural "PDFtk: Marking page %d of all stacks." #~ msgstr[0] "pdftk: Criando marca d'água na página %d de todas as folhas." #~ msgstr[1] "pdftk: Criando marca d'água na página %d de todas as folhas." #~ msgid "pdftk: Assembling everything into the final PDF." #~ msgstr "pdftk: Montando tudo no PDF final." #, fuzzy #~ msgid "Marking using pyPdf. For faster marking, install PDFtk." #~ msgstr "" #~ "Estampando com pyPdf. Para estampar mais rapidamente, instale o pdftk." sdaps-1.9.8/po/pt_BR.po0000644000175000000660000012652113456636461015410 0ustar benjaminlock00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: SDAPS 0.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:10+0100\n" "PO-Revision-Date: 2019-04-18 22:07+0000\n" "Last-Translator: Rui Mendes \n" "Language-Team: Portuguese (Brazil) \n" "Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 3.6-dev\n" #: ../sdaps/script.py:41 msgid "SDAPS -- Paper based survey tool." msgstr "SDAPS -- Ferramenta de questionários baseados em papel." #: ../sdaps/script.py:45 msgid "command list|Commands:" msgstr "lista de comandos|Comandos:" #: ../sdaps/script.py:50 msgid "project directory|The SDAPS project." msgstr "diretório do projeto|Projeto SDAPS." #: ../sdaps/add/__init__.py:55 #, python-format msgid "" "Invalid input file %s. You need to specify a (multipage) monochrome TIFF as " "input." msgstr "" "Arquivo de entrada inválido %s. Você precisa especificar uma imagem TIFF " "(multipáginas) monocromática como entrada." #: ../sdaps/add/__init__.py:67 #, python-format msgid "" "Not adding %s because it has a wrong page count (needs to be a mulitple of " "%i)." msgstr "" "Não adicionando %s porque ele tem um número de páginas errado (deve ser um " "múltiplo de %i)." #: ../sdaps/boxgallery/__init__.py:108 #, python-format msgid "Rendering boxgallery for metric \"%s\"." msgstr "Renderizando caixas pela métrica \"%s\"." #: ../sdaps/log.py:37 msgid "Warning: " msgstr "Atenção: " #: ../sdaps/log.py:41 msgid "Error: " msgstr "Erro: " #: ../sdaps/cmdline/add.py:31 msgid "Add scanned questionnaires to the survey." msgstr "Adicionar questionários digitalizados na pesquisa." #: ../sdaps/cmdline/add.py:32 msgid "" "This command is used to add scanned images to the survey.\n" " The image data needs to be a (multipage) 300dpi monochrome TIFF file. " "You\n" " may choose not to copy the data into the project directory. In that " "case\n" " the data will be referenced using a relative path." msgstr "" "Este comando é usado para adicionar imagens digitalizadas na pesquisa.\n" " A imagem precisa ser em formato TIFF (multipáginas) monocromático de " "300dpi.\n" " Você pode optar por não copiar os dados para o diretório do projeto. " "Nesse\n" " caso os dados serão referenciados usando um caminho relativo." #: ../sdaps/cmdline/add.py:38 msgid "Convert given files and add the result." msgstr "Converter os arquivos fornecidos e adicionar o resultado." #: ../sdaps/cmdline/add.py:43 msgid "" "Do a 3D-transformation after finding the corner marks. If the\n" " corner marks are not found then the image will be added as-is." msgstr "" "Faz uma transformação 3D depois de encontrar as marcas de canto.\n" " Se as marcas não forem encontradas, a imagem é adicionada como é." #: ../sdaps/cmdline/add.py:49 msgid "" "Force adding the images even if the page count is wrong (only use if you " "know what you are doing)." msgstr "" "Força a adição das imagens, mesmo que a contagem de páginas esteja errada " "(só use se você sabe o que está fazendo)." #: ../sdaps/cmdline/add.py:53 msgid "Copy the files into the directory (default)." msgstr "Copie os arquivos para o diretório (padrão)." #: ../sdaps/cmdline/add.py:58 msgid "Do not copy the files into the directory." msgstr "Não copie os arquivos para o diretório." #: ../sdaps/cmdline/add.py:62 msgid "" "Images contain a duplex scan of a simplex questionnaire (default: simplex " "scan)." msgstr "" "As imagens contêm uma digitalização duplex de um questionário simplex " "(padrão: digitalização simplex)." #: ../sdaps/cmdline/add.py:68 ../sdaps/cmdline/convert.py:48 msgid "A number of TIFF image files." msgstr "Um número de arquivos de imagem TIFF." #: ../sdaps/cmdline/add.py:94 msgid "The --no-copy option is not compatible with --convert!" msgstr "A opção --no-copy não é compatível com --convert!" #: ../sdaps/cmdline/add.py:103 msgid "Converting input files into a single temporary file." msgstr "Converter arquivos de entrada em um diretório temporário." #: ../sdaps/cmdline/add.py:115 msgid "" "The page count of the created temporary file does not work with this survey." msgstr "" "A imagem convertida não tem o formato correto. O número de páginas está " "errado." #: ../sdaps/cmdline/add.py:120 msgid "Running the conversion failed." msgstr "A conversão falhou." #: ../sdaps/cmdline/add.py:126 #, python-format msgid "Processing %s" msgstr "Processando %s" #: ../sdaps/cmdline/add.py:130 ../sdaps/reset/__init__.py:33 msgid "Done" msgstr "Concluído" #: ../sdaps/cmdline/annotate.py:28 msgid "Annotate the questionnaire and show the recognized positions." msgstr "Anotar o questionário e mostrar as posições reconhecidas." #: ../sdaps/cmdline/annotate.py:29 msgid "" "This command is mainly a debug utility. It creates an\n" " annotated version of the questionnaire, with the information that SDAPS\n" " knows about it overlayed on top." msgstr "" "Este comando é principalmente um utilitário de depuração. Ele cria uma\n" " versão anotada do questionário, com as informações que o SDAPS\n" " sabe sobre ele sobrepostas na parte superior." #: ../sdaps/cmdline/boxgallery.py:31 msgid "Create PDFs with boxes sorted by the detection heuristics." msgstr "Cria PDFs com caixas ordenadas por heurísticas de detecção." #: ../sdaps/cmdline/boxgallery.py:32 msgid "" "SDAPS uses multiple heuristics to detect determine the\n" " state of checkboxes. There is a list for each heuristic giving the " "expected\n" " state and the quality of the value (see defs.py). Using this command a " "PDF\n" " will be created for each of the heuristics so that one can adjust the\n" " values." msgstr "" "O SDAPS usa várias heurísticas para determinar o estado das caixas.\n" " Há uma lista para cada heurística dando o estado esperado e a qualidade\n" " do valor (ver defs.py). Usando este comando um PDF será criado para " "cada\n" " uma das heurísticas, para que se possa ajustar os valores." #: ../sdaps/cmdline/boxgallery.py:40 msgid "" "Reruns part of the recognition process and retrieves debug images from this " "step." msgstr "" "Executa o reconhecimento novamente e armazena imagens adicionais para " "depuração a partir deste passo." #: ../sdaps/cmdline/convert.py:30 msgid "Convert a set of images to the correct image format." msgstr "Converte um conjunto de imagens para o formato de imagem correto." #: ../sdaps/cmdline/convert.py:31 #, fuzzy msgid "" "This command can be used if you scanned files in something\n" " other than the expected monochrome TIFF mode. All given files will\n" " be loaded, converted to monochrome and stored in a multipage 1bpp\n" " TIFF file. Optionally, you can select \"3D transformation\"\\ ,which " "may facilitate\n" " working with photos of questionnaires instead of scans." msgstr "" "Esse comando pode ser usado se você tiver arquivos digitalizados em formato " "diferente\n" "\tao TIFF monocromático esperado. Todos os arquivos serão carregados,\n" "\tconvertidos em monocromático e armazenados em um arquivo TIFF multipágina " "de 1bpp.\n" "\tOpcionalmente, você pode selecionar que se realize uma transformação 3D,\n" "\tcom isto pode ser possível trabalhar com fotos dos questionários, ao " "invés\n" "\tda digitalização convencional." #: ../sdaps/cmdline/convert.py:38 #, fuzzy msgid "" "Do a 3D-transformation after finding the corner marks.\n" " If they are not found, the image will be processed as-is." msgstr "" "Faz uma transformação 3D depois de encontrar as marcas de canto.\n" " Se as marcas não forem encontradas, a imagem é adicionada como é." #: ../sdaps/cmdline/convert.py:44 #, fuzzy msgid "The location of the output file." msgstr "A localização do arquivo de saída. Deve ser fornecida." #: ../sdaps/cmdline/convert.py:57 msgid "No output filename specified!" msgstr "Nome do arquivo de saída não especificado!" #: ../sdaps/cmdline/cover.py:27 msgid "Create a cover for the questionnaires." msgstr "Criar uma página de rosto para os questionários." #: ../sdaps/cmdline/cover.py:28 msgid "" "This command creates a cover page for questionnaires. All\n" " the metadata of the survey will be printed on the page." msgstr "" "Este comando cria uma página de rosto para os questionários.\n" " Todos os metadados da pesquisa serão impressos nela." #: ../sdaps/cmdline/cover.py:31 #, python-format msgid "Filename to store the data to (default: cover_%%i.pdf)" msgstr "Nome de arquivo para armazenar os dados (padrão: cover_%%i.pdf)" #: ../sdaps/cmdline/csvdata.py:34 msgid "Import or export data to/from CSV files." msgstr "Importar ou exportar dados de/para arquivos CSV." #: ../sdaps/cmdline/csvdata.py:35 msgid "" "Import or export data to/from a CSV file. The first line\n" " is a header which defines questionnaire_id and global_id, and a column\n" " for each checkbox and textfield. Note that the import is currently very\n" " limited, as you need to specifiy the questionnaire ID to select the " "sheet\n" " which should be updated." msgstr "" "Importar ou exportar dados de/para um arquivo CSV. A primeira linha\n" " é um cabeçalho, que define questionnaire_id, global_id e uma coluna\n" " para cada caixa de seleção e campo de texto. Note que a importação é\n" " atualmente muito limitada, já que você precisa especificar o " "identificador\n" " do questionário para selecionar a folha que deverá ser atualizada." #: ../sdaps/cmdline/csvdata.py:44 msgid "Export data to CSV file." msgstr "Exportar dados para arquivo CSV." #: ../sdaps/cmdline/csvdata.py:46 #, python-format msgid "Filename to store the data to (default: data_%%i.csv)" msgstr "Nome de arquivo para armazenar os dados (padrão: data_%%i.csv)" #: ../sdaps/cmdline/csvdata.py:48 msgid "The delimiter used in the CSV file (default ',')" msgstr "O delimitador usado no arquivo CSV (padrão ',')" #: ../sdaps/cmdline/csvdata.py:52 ../sdaps/cmdline/report.py:31 #: ../sdaps/cmdline/reporttex.py:52 msgid "Filter to only export a partial dataset." msgstr "Filtro para exportar apenas um conjunto de dados parcial." #: ../sdaps/cmdline/csvdata.py:54 msgid "Export images of freeform fields." msgstr "Exportar imagens dos campos de forma livre." #: ../sdaps/cmdline/csvdata.py:60 msgid "Export an image for each question that includes all boxes." msgstr "Exportar uma imagem para cada pergunta que inclui todas as caixas." #: ../sdaps/cmdline/csvdata.py:66 msgid "Export the recognition quality for each checkbox." msgstr "Exportar a qualidade de reconhecimento para cada caixa de verificação." #: ../sdaps/cmdline/csvdata.py:74 msgid "Import data to from a CSV file." msgstr "Importar dados de um arquivo CSV." #: ../sdaps/cmdline/csvdata.py:76 msgid "The file to import." msgstr "O arquivo a ser importado." #: ../sdaps/cmdline/gui.py:28 #, fuzzy msgid "Launch a GUI. You can view and alter the (recognized) answers with it." msgstr "" "Abrir uma interface gráfica (GUI). Você pode visualizar e alterar as " "respostas (reconhecidas) nela." #: ../sdaps/cmdline/gui.py:29 #, fuzzy msgid "" "This command launches a graphical user interface that can\n" " be used to correct answers. You need to run \"recognize\" before using " "it.\n" " " msgstr "" "Este comando lança uma interface gráfica (GUI) que pode ser utilizada para\n" " corrigir respostas. Você precisa executar \"recognize\" antes de usá-" "lo.\n" " " #: ../sdaps/cmdline/gui.py:34 msgid "Filter to only show a partial dataset." msgstr "Filtro para mostrar apenas um conjunto de dados parcial." #: ../sdaps/cmdline/ids.py:29 msgid "Export and import questionnaire IDs." msgstr "Exportação e importação de IDs de questionário." #: ../sdaps/cmdline/ids.py:30 msgid "" "This command can be used to import and export questionnaire\n" " IDs. It only makes sense in projects where such an ID is printed on the\n" " questionnaire. Note that you can also add IDs by using the stamp " "command,\n" " which will give you the PDF at the same time." msgstr "" "Esse comando pode ser usado para importar e exportar IDs de questionário.\n" " Ele só faz sentido em projetos onde tal identificação é impressa no\n" " questionário. Note que você também pode adicionar IDs usando o comando\n" " \"stamp\", que também lhe dará o arquivo PDF." #: ../sdaps/cmdline/ids.py:35 #, python-format msgid "Filename to store the data to (default: ids_%%i)" msgstr "Nome de arquivo para armazenar os dados (padrão: ids_%%i)" #: ../sdaps/cmdline/ids.py:38 msgid "Add IDs to the internal list from the specified file." msgstr "Adicionar IDs à lista interna do arquivo especificado." #: ../sdaps/cmdline/info.py:28 msgid "Display and modify metadata of project." msgstr "Exibir e modificar os metadados do projeto." #: ../sdaps/cmdline/info.py:29 msgid "" "This command lets you modify the metadata of the SDAPS\n" " project. You can modify, add and remove arbitrary keys that will be " "printed\n" " on the report. The only key that always exist is \"title\".\n" " If no key is given then a list of defined keys is printed." msgstr "" "Este comando permite que você modifique os metadados do projeto SDAPS.\n" " Você pode modificar, adicionar e remover chaves arbitrárias que serão " "impressas\n" " no relatório. A única chave que sempre existe é \"title\".\n" " Se nenhuma chave for informada, uma lista de chaves definidas é " "impressa." #: ../sdaps/cmdline/info.py:36 msgid "Delete the key and value pair." msgstr "Exclua o par de chave e valor." #: ../sdaps/cmdline/info.py:40 msgid "The key to display or modify." msgstr "A chave para exibir ou modificar." #: ../sdaps/cmdline/info.py:44 msgid "Set the given key to this value." msgstr "Novo valor para a chave." #: ../sdaps/cmdline/info.py:69 msgid "Existing fields:\n" msgstr "Campos existentes:\n" #: ../sdaps/cmdline/recognize.py:28 msgid "Run the optical mark recognition." msgstr "Executar o reconhecimento óptico de marcas." #: ../sdaps/cmdline/recognize.py:29 msgid "" "Iterates over all images and runs the optical mark\n" " recognition. It will reevaluate sheets even if \"recognize\" has " "already\n" " run or manual changes were made." msgstr "" "Itera sobre todas as imagens e executa o reconhecimento óptico de marcas.\n" " Ele irá reavaliar as folhas mesmo se o comando \"recognize\" for\n" " executado previamente ou alterações manuais tenham sido feitas." #: ../sdaps/cmdline/recognize.py:34 msgid "" "Only identify the page properties, but don't recognize the checkbox states." msgstr "Analisa apenas as propriedades da página, mas não as respostas." #: ../sdaps/cmdline/recognize.py:39 msgid "" "Rerun the recognition for all pages. The default is to skip all pages that " "were recognized or verified already." msgstr "" "Execute novamente o reconhecimento para todas as páginas. O padrão é pular " "todas as páginas que já foram reconhecidas ou verificadas." #: ../sdaps/cmdline/reorder.py:26 msgid "Reorder pages according to questionnaire ID." msgstr "Reordenar páginas de acordo com o ID do questionário." #: ../sdaps/cmdline/reorder.py:27 msgid "" "This command reorders all pages according to the already\n" " recognized questionnaire ID. To use it add all the files to the " "project,\n" " then run a partial recognition using \"recognize --identify\". After " "this\n" " you have to run this command to reorder the data for the real " "recognition.\n" " " msgstr "" "Este comando reordena as páginas pelo ID do questionário já reconhecido\n" " Para usá-lo, adicione todos os arquivos ao projeto, depois\n" " execute o reconhecimento parcial com \"recognize --identify\".\n" " Logo após, você precisa executar este comando para reordenar\n" " os dados para o real reconhecimento.\n" " " #: ../sdaps/cmdline/report.py:26 msgid "Create a PDF report." msgstr "Criar um relatório PDF." #: ../sdaps/cmdline/report.py:27 msgid "" "This command creates a PDF report using reportlab that\n" " contains statistics and if selected the freeform fields." msgstr "" "Este comando cria um relatório em PDF usando reportlab que\n" " contém estatísticas e os campos de forma livre, se selecionados." #: ../sdaps/cmdline/report.py:33 msgid "Create a filtered report for every checkbox." msgstr "Criar um relatório filtrado para cada caixa." #: ../sdaps/cmdline/report.py:36 msgid "Short format (without freeform text fields)." msgstr "Formato curto (sem campos de texto de forma livre)." #: ../sdaps/cmdline/report.py:41 msgid "Detailed output. (default)" msgstr "Saída detalhada. (padrão)" #: ../sdaps/cmdline/report.py:47 ../sdaps/cmdline/reporttex.py:30 msgid "" "Do not include original images in the report. This is useful if there are " "privacy concerns." msgstr "" "Não incluir imagens originais no relatório. Isso é útil se houver " "preocupações com a privacidade." #: ../sdaps/cmdline/report.py:52 ../sdaps/cmdline/reporttex.py:35 msgid "Do not use substitutions instead of images." msgstr "Não use substituições em vez de imagens." #: ../sdaps/cmdline/report.py:58 ../sdaps/cmdline/reporttex.py:46 msgid "The paper size used for the output (default: locale dependent)" msgstr "" "O tamanho do papel usado para a saída (padrão: dependente da localidade)" #: ../sdaps/cmdline/report.py:61 ../sdaps/cmdline/reporttex.py:49 #, python-format msgid "Filename to store the data to (default: report_%%i.pdf)" msgstr "Nome de arquivo para armazenar os dados (padrão: report_%%i.pdf)" #: ../sdaps/cmdline/reporttex.py:26 msgid "Create a PDF report using LaTeX." msgstr "Criar um relatório em PDF usando LaTeX." #: ../sdaps/cmdline/reporttex.py:27 msgid "" "This command creates a PDF report using LaTeX that\n" " contains statistics and freeform fields." msgstr "" "Este comando cria um relatório em PDF usando LaTeX que\n" " contém estatísticas e campos de forma livre." #: ../sdaps/cmdline/reporttex.py:41 msgid "Save the generated TeX files instead of the final PDF." msgstr "Salve os arquivos TeX gerados em vez do PDF final." #: ../sdaps/cmdline/reset.py:26 msgid "Reset project into original state" msgstr "" #: ../sdaps/cmdline/reset.py:27 msgid "" "This command does a full reset of the project. All data\n" " will be discarded and only the empty project is left.\n" " " msgstr "" #: ../sdaps/cmdline/setup.py:27 msgid "Create a new survey using a LaTeX document." msgstr "Criar uma nova pesquisa através de um documento LaTeX." #: ../sdaps/cmdline/setup.py:28 msgid "" "Create a new survey from a LaTeX document. You need to\n" " be using the SDAPS class. All the metadata and options for the project\n" " can be set inside the LaTeX document." msgstr "" "Criar uma nova pesquisa de um documento LaTeX. Você deve\n" " utilizar a classe SDAPS. Todos os metadados e opções\n" " para o projeto podem ser definidos no documento LaTeX." #: ../sdaps/cmdline/setup.py:33 msgid "The LaTeX Document" msgstr "O documento LaTeX" #: ../sdaps/cmdline/setup.py:35 msgid "" "Additional files that are required by the LaTeX document and need to be " "copied into the project directory." msgstr "" "Arquivos adicionais são necessários para o documento LaTeX e precisam ser " "copiados para o diretório do projeto." #: ../sdaps/cmdline/setup.py:39 msgid "Additional questions that are not part of the questionnaire." msgstr "Outras perguntas que não fazem parte do questionário." #: ../sdaps/cmdline/stamp.py:26 msgid "Add marks for automatic processing." msgstr "Adicionar marcas para processamento automático." #: ../sdaps/cmdline/stamp.py:27 msgid "" "This command creates the printable document. Depending on\n" " the projects setting you are required to specifiy a source for " "questionnaire\n" " IDs." msgstr "" "Este comando cria o documento para impressão. Dependendo das configurações\n" " do projeto, você deve especificar uma fonte para os IDs de " "questionário." #: ../sdaps/cmdline/stamp.py:33 msgid "" "If using questionnaire IDs, create N questionnaires with randomized IDs." msgstr "" "Se estiver usando IDs de questionário, cria N questionários com IDs " "aleatórios." #: ../sdaps/cmdline/stamp.py:36 msgid "" "If using questionnaire IDs, create questionnaires from the IDs read from the " "specified file." msgstr "" "Se estiver usando IDs de questionário, cria questionários com os IDs lidos " "do arquivo especificado." #: ../sdaps/cmdline/stamp.py:39 msgid "If using questionnaire IDs, create questionnaires for all stored IDs." msgstr "" "Se estiver usando IDs de questionário, cria questionários para todos os IDs " "armazenados." #: ../sdaps/cmdline/stamp.py:42 #, python-format msgid "Filename to store the data to (default: stamp_%%i.pdf)" msgstr "Nome de arquivo para armazenar os dados (padrão: stamp_%%i.pdf)" #: ../sdaps/convert/__init__.py:37 #, python-format msgid "Could not apply 3D-transformation to image '%s', page %i!" msgstr "Não foi possível aplicar transformação 3D na imagem '%s', página %i!" #: ../sdaps/cover/__init__.py:40 #, fuzzy msgid "SDAPS questionnaire" msgstr "questionário sdaps" #: ../sdaps/csvdata/buddies.py:77 #, fuzzy, python-format msgid "Not importing unknown questionnaire ID \"%s\"" msgstr "Exportação e importação de IDs de questionário." #: ../sdaps/gui/__init__.py:59 msgid "" "The survey does not have any images! Please add images (and run recognize) " "before using the GUI." msgstr "" "A pesquisa não possui imagens! Por favor, adicione imagens e execute " "\"recognize\" antes de usar a interface gráfica (GUI)." #: ../sdaps/gui/__init__.py:211 msgid "Page|Invalid" msgstr "Página|Inválida" #: ../sdaps/gui/__init__.py:214 #, python-format msgid "Page %i" msgid_plural "Page %i" msgstr[0] "Página %i" msgstr[1] "Página %i" #: ../sdaps/gui/__init__.py:256 msgid "Copyright © 2007-2014 The SDAPS Authors" msgstr "Copyright © 2007-2014 Os autores do SDAPS" #: ../sdaps/gui/__init__.py:258 msgid "Scripts for data acquisition with paper based surveys" msgstr "SDAPS - Scripts para aquisição de dados de pesquisas baseadas em papel" #: ../sdaps/gui/__init__.py:259 msgid "http://sdaps.org" msgstr "http://sdaps.org" #: ../sdaps/gui/__init__.py:260 msgid "translator-credits" msgstr "Rodrigo Antonio Müller" #: ../sdaps/gui/__init__.py:305 #, python-format msgid " of %i" msgstr " de %i" #: ../sdaps/gui/__init__.py:306 #, python-format msgid "Recognition Quality: %.2f" msgstr "Qualidade de reconhecimento: %.2f" #: ../sdaps/gui/__init__.py:322 msgid "" "You have reached the first page of the survey. Would you like to go to the " "last page?" msgstr "" "Você chegou na primeira página da pesquisa. Deseja ir para a última página?" #: ../sdaps/gui/__init__.py:324 msgid "Go to last page" msgstr "Ir para a última página" #: ../sdaps/gui/__init__.py:346 msgid "" "You have reached the last page of the survey. Would you like to go to the " "first page?" msgstr "" "Você chegou na última página da pesquisa. Deseja ir para a primeira página?" #: ../sdaps/gui/__init__.py:348 msgid "Go to first page" msgstr "Ir para a primeira página" #: ../sdaps/gui/__init__.py:457 msgid "Close without saving" msgstr "Fechar sem salvar" #: ../sdaps/gui/__init__.py:461 msgid "" "Save the project before closing?\n" "\n" "If you do not save you may loose data." msgstr "" "Deseja salvar o projeto antes de fechar?\n" "\n" "Se não salvar, poderá perder dados." #: ../sdaps/gui/main_window.ui.h:1 msgid "Forward" msgstr "Próximo" #: ../sdaps/gui/main_window.ui.h:2 msgid "Previous" msgstr "Anterior" #: ../sdaps/gui/main_window.ui.h:3 msgid "Zoom In" msgstr "Ampliar" #: ../sdaps/gui/main_window.ui.h:4 msgid "Zoom Out" msgstr "Reduzir" #: ../sdaps/gui/main_window.ui.h:5 msgid "SDAPS" msgstr "SDAPS" #: ../sdaps/gui/main_window.ui.h:6 msgid "_File" msgstr "_Arquivo" #: ../sdaps/gui/main_window.ui.h:7 msgid "_View" msgstr "_Exibir" #: ../sdaps/gui/main_window.ui.h:8 msgid "_Help" msgstr "_Ajuda" #: ../sdaps/gui/main_window.ui.h:9 msgid "Page Rotated" msgstr "Página Girada" #: ../sdaps/gui/main_window.ui.h:10 msgid "Sort by Quality" msgstr "Ordenar pela Qualidade" #: ../sdaps/gui/main_window.ui.h:11 msgid "label" msgstr "Rótulo" #: ../sdaps/gui/widget_buddies.py:56 msgid "Global Properties" msgstr "Propriedades Globais" #: ../sdaps/gui/widget_buddies.py:60 msgid "Sheet valid" msgstr "Folha válida" #: ../sdaps/gui/widget_buddies.py:61 #, fuzzy msgid "Sheet Verified" msgstr "Verificado" #: ../sdaps/gui/widget_buddies.py:62 #, fuzzy msgid "Page Verified" msgstr "Verificado" #: ../sdaps/gui/widget_buddies.py:63 msgid "Empty" msgstr "Vazio" #: ../sdaps/gui/widget_buddies.py:75 ../sdaps/gui/widget_buddies.py:105 msgid "Questionnaire ID: " msgstr "ID do Questionário: " #: ../sdaps/image/__init__.py:47 msgid "" "It appears you have not build the C extension. Please run \"./setup.py build" "\" in the toplevel directory." msgstr "" "Parece que você não construiu a extensão C. Por favor, execute \"./setup.py " "build\" no diretório principal." #: ../sdaps/utils/latex.py:29 msgid "" "The latex character map is missing! Please build it using the supplied tool " "(create-latexmap.py)." msgstr "" #: ../sdaps/utils/latex.py:69 msgid "" "Generated string for LaTeX contains unicode characters. This may not work " "correctly and could mean the LaTeX character map needs to be updated." msgstr "" #: ../sdaps/utils/opencv.py:35 msgid "Cannot convert PDF files as poppler is not installed or usable!" msgstr "" "Não é possível converter arquivos PDF, pois o poppler não está instalado ou " "utilizável!" #: ../sdaps/utils/opencv.py:44 msgid "File does not exist" msgstr "" #. The old code used to first filter, and then run; but that is #. a bit ineffective in a way #: ../sdaps/model/survey.py:386 #, python-format msgid "%i sheet" msgid_plural "%i sheets" msgstr[0] "%i folha" msgstr[1] "%i folhas" #: ../sdaps/model/survey.py:402 #, python-format msgid "Processed %i of %i sheets, took %f seconds" msgstr "" #: ../sdaps/model/survey.py:449 msgid "" "A questionnaire that is printed in duplex needs an even amount of pages!" msgstr "" "Um questionário impresso em duplex necessita de uma quantidade par de " "páginas!" #: ../sdaps/model/survey.py:453 msgid "" "The 'classic' style only supports a maximum of six pages! Use the 'code128' " "style if you require more pages." msgstr "" "O estilo 'classic' suporta apenas seis páginas no máximo! Use o estilo " "'code128' se você precisa de mais páginas." #: ../sdaps/model/survey.py:466 msgid "IDs need to be integers in \"classic\" style!" msgstr "IDs precisam ser números inteiros no estilo \"clássico\"!" #: ../sdaps/model/survey.py:472 #, python-format msgid "Invalid character %s in questionnaire ID \"%s\" in \"code128\" style!" msgstr "" "Caractere inválido %s no ID de questionário \"%s\" com estilo \"code128\"!" #: ../sdaps/model/survey.py:476 msgid "" "SDAPS cannot draw a questionnaire ID with the \"custom\" style. Do this " "yourself somehow!" msgstr "" "SDAPS não pode desenhar um ID de questionário com o estilo \"custom\". Faça " "isto de alguma forma!" #. in simplex mode every page will have a matrix; it might be a None #. matrix though #: ../sdaps/recognize/buddies.py:71 #, python-format msgid "%s, %i: Matrix not recognized." msgstr "%s, %i: Matriz não reconhecida." #: ../sdaps/recognize/buddies.py:80 #, python-format msgid "%s, %i: Rotation not found." msgstr "%s, %i: Rotação não detectada." #. Copy the rotation over (if required) and print warning if the rotation is unknown #: ../sdaps/recognize/buddies.py:84 #, python-format msgid "Neither %s, %i or %s, %i has a known rotation!" msgstr "Nem %s, %i ou %s, %i tem uma rotação conhecida!" #: ../sdaps/recognize/buddies.py:96 #, python-format msgid "%s, %i: Matrix not recognized (again)." msgstr "%s, %i: Matriz não reconhecida (novamente)." #: ../sdaps/recognize/buddies.py:110 #, python-format msgid "%s, %i: Could not get page number." msgstr "%s, %i: Não foi possível obter o número da página." #. Whoa, that should not happen. #: ../sdaps/recognize/buddies.py:130 #, python-format msgid "Neither %s, %i or %s, %i has a known page number!" msgstr "Nem %s, %i ou %s, %i tem um número de página conhecido!" #. We don't touch the ignore flag in this case #. Simply print a message as this should *never* happen #: ../sdaps/recognize/buddies.py:141 #, python-format msgid "" "Got a simplex document where two adjacent pages had a known page number. " "This should never happen as even simplex scans are converted to duplex by " "inserting dummy pages. Maybe you did a simplex scan but added it in duplex " "mode? The pages in question are %s, %i and %s, %i." msgstr "" "Tenho um documento simplex, onde duas páginas adjacentes tem um número de " "página conhecido. Isso nunca deveria acontecer, pois mesmo as varreduras " "simplex são convertidas para duplex, com a inserção de páginas falsas. Será " "que você fez uma varredura simplex, mas a adicionou em modo duplex? As " "páginas em questão são %s, %i e %s, %i." #: ../sdaps/recognize/buddies.py:158 #, python-format msgid "Images %s, %i and %s, %i do not have consecutive page numbers!" msgstr "Imagens %s, %i e %s, %i não tem números de página consecutivos!" #: ../sdaps/recognize/buddies.py:174 #, python-format msgid "No page number for page %s, %i exists." msgstr "Não existe número de página para a página %s, %i." #: ../sdaps/recognize/buddies.py:179 #, python-format msgid "Page number for page %s, %i already used by another image." msgstr "" "O número de página para a página %s, %i já é utilizado por outra imagem." #: ../sdaps/recognize/buddies.py:185 #, python-format msgid "Page number %i for page %s, %i is out of range." msgstr "O número de página %i para a página %s, %i está fora do intervalo." #: ../sdaps/recognize/buddies.py:202 #, python-format msgid "%s, %i: Could not read survey ID, but should be able to." msgstr "" "%s, %i: Não foi possível ler o ID da pesquisa, mas deve ser capaz de fazer." #: ../sdaps/recognize/buddies.py:206 #, python-format msgid "Could not read survey ID of either %s, %i or %s, %i!" msgstr "Não foi possível ler o ID da pesquisa de %s, %i ou %s, %i!" #. Broken survey ID ... #: ../sdaps/recognize/buddies.py:213 #, python-format msgid "Got a wrong survey ID (%s, %i)! It is %s, but should be %i." msgstr "Tem um ID de pesquisa errado (%s, %i)! É %s, mas deve ser %i." #: ../sdaps/recognize/buddies.py:235 #, python-format msgid "%s, %i: Could not read questionnaire ID, but should be able to." msgstr "" "%s, %i: Não foi possível ler o ID do questionário, mas deve ser capaz de " "fazer." #: ../sdaps/recognize/buddies.py:241 #, python-format msgid "Could not read questionnaire ID of either %s, %i or %s, %i!" msgstr "Não foi possível ler o ID de questionário de %s, %i ou %s, %i!" #: ../sdaps/recognize/buddies.py:271 msgid "" "Got different IDs on different pages for at least one sheet! Do *NOT* try to " "use filters with this survey! You have to run a \"reorder\" step for this to " "work properly!" msgstr "" "Tem diferentes IDs em páginas diferentes para pelo menos uma folha! *NÃO* " "tente usar filtros com esta pesquisa! Você precisa executar o passo \"reorder" "\" para que isso funcione corretamente!" #: ../sdaps/recognize/buddies.py:326 msgid "No style buddy loaded. This needs to be done for the \"custom\" style!" msgstr "" "Não há definição de estilo carregada. Isto precisa ser feito para o estilo " "\"custom\"!" #: ../sdaps/report/answers.py:188 #, python-format msgid "Answers: %i" msgstr "Respostas: %i" #: ../sdaps/report/answers.py:190 #, python-format msgid "Mean: %.2f" msgstr "Média: %.2f" #: ../sdaps/report/answers.py:192 #, python-format msgid "Standard Deviation: %.2f" msgstr "Desvio Padrão: %.2f" #: ../sdaps/report/__init__.py:75 ../sdaps/reporttex/__init__.py:140 msgid "Turned in Questionnaires" msgstr "Quantidade de questionários" #: ../sdaps/report/__init__.py:92 ../sdaps/reporttex/__init__.py:139 msgid "sdaps report" msgstr "Relatório SDAPS" #: ../sdaps/reset/__init__.py:29 msgid "Removing stored data..." msgstr "" #: ../sdaps/setup/buddies.py:62 #, python-format msgid "Head %(l0)i got no title." msgstr "O cabeçalho %(l0)i não tem título." #: ../sdaps/setup/buddies.py:74 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no question." msgstr "%(class)s %(l0)i.%(l1)i não possui qualquer questão." #: ../sdaps/setup/buddies.py:114 #, python-format msgid "Error in question \"%s\"" msgstr "Erro na questão \"%s\"" #: ../sdaps/setup/buddies.py:118 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no boxes." msgstr "%(class)s %(l0)i.%(l1)i não possui caixas." #: ../sdaps/setup/buddies.py:167 #, fuzzy, python-format msgid "%(class)s %(l0)i.%(l1)i lower box out of range." msgstr "%(class)s %(l0)i.%(l1)i não possui qualquer questão." #: ../sdaps/setup/buddies.py:172 #, fuzzy, python-format msgid "%(class)s %(l0)i.%(l1)i upper box out of range." msgstr "%(class)s %(l0)i.%(l1)i não possui caixas." #: ../sdaps/setup/buddies.py:177 #, fuzzy, python-format msgid "%(class)s %(l0)i.%(l1)i lower box not before upper box." msgstr "%(class)s %(l0)i.%(l1)i não tem exatamente uma caixa." #: ../sdaps/setup/buddies.py:213 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly two answers." msgstr "%(class)s %(l0)i.%(l1)i não tem exatamente duas respostas." #: ../sdaps/setup/buddies.py:234 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly one box." msgstr "%(class)s %(l0)i.%(l1)i não tem exatamente uma caixa." #: ../sdaps/stamp/__init__.py:38 msgid "" "You may not specify the number of sheets for this survey. All questionnaires " "will be identical as the survey has been configured to not use questionnaire " "IDs for each sheet." msgstr "" "Você não pode especificar o número de folhas para esta pesquisa. Todos os " "questionários serão idênticos já que a pesquisa foi configurada para não " "usar IDs de questionário em cada folha." #: ../sdaps/stamp/__init__.py:76 msgid "" "This survey has been configured to use questionnaire IDs. Each questionnaire " "will be unique. You need to use on of the options to add new IDs or use the " "existing ones." msgstr "" "Esta pesquisa foi configurada para usar IDs de questionário. Cada " "questionário será único. Por isso, uma das opções deve ser usada, para " "adicionar novos IDs ou usar já armazenados." #: ../sdaps/stamp/latex.py:18 msgid "" "There should be no need to stamp a SDAPS Project that uses LaTeX and does " "not have different questionnaire IDs printed on each sheet.\n" "I am going to do so anyways." msgstr "" "Não deveria ser necessário estampar um projeto SDAPS que usa LaTeX e não tem " "diferentes IDs de questionário impresso em cada folha.\n" "Vou fazê-lo de qualquer maneira." #: ../sdaps/stamp/latex.py:26 #, python-format msgid "Running %s now twice to generate the stamped questionnaire." msgstr "Executando %s duas vezes para gerar o questionário estampado." #: ../sdaps/stamp/latex.py:30 ../sdaps/setuptex/__init__.py:107 #: ../sdaps/setuptex/__init__.py:148 ../sdaps/reporttex/__init__.py:162 #, python-format msgid "Error running \"%s\" to compile the LaTeX file." msgstr "Erro executando \"%s\" para compilar o arquivo LaTeX." #: ../sdaps/stamp/latex.py:36 #, python-format msgid "" "An error occured during creation of the report. Temporary files left in '%s'." msgstr "" "Ocorreu um erro durante a criação do relatório. Os arquivos temporários " "foram deixados em '%s'." #: ../sdaps/setuptex/__init__.py:46 msgid "The survey directory already exists." msgstr "O diretório da pesquisa já existe." #: ../sdaps/setuptex/__init__.py:51 #, python-format msgid "Unknown file type (%s). questionnaire_tex should be of type text/x-tex." msgstr "" "Tipo de arquivo desconhecido (%s). O questionnaire_tex deve ser do tipo text/" "x-tex." #: ../sdaps/setuptex/__init__.py:52 msgid "Will keep going, but expect failure!" msgstr "Vai continuar, mas espere por falhas!" #: ../sdaps/setuptex/__init__.py:57 #, python-format msgid "Unknown file type (%s). additionalqobjects should be text/plain." msgstr "" "Tipo de arquivo desconhecido (%s). O additionalqobjects deve ser do tipo " "text/plain." #: ../sdaps/setuptex/__init__.py:103 ../sdaps/setuptex/__init__.py:143 #, python-format msgid "Running %s now twice to generate the questionnaire." msgstr "Executando %s duas vezes para gerar o questionário." #: ../sdaps/setuptex/__init__.py:122 msgid "Caught an Exception while parsing the SDAPS file. The current state is:" msgstr "Houve uma exceção ao analisar o arquivo SDAPS. O estado atual é:" #: ../sdaps/setuptex/__init__.py:136 msgid "" "Some combination of options and project properties do not work. Aborted " "Setup." msgstr "" "Uma combinação de opções e propriedades do projeto não funcionam. Instalação " "abortada." #: ../sdaps/setuptex/__init__.py:162 msgid "" "An error occured in the setup routine. The survey directory still exists. " "You can for example check the questionnaire.log file for LaTeX compile " "errors." msgstr "" "Ocorreu um erro na rotina de instalação. O diretório de pesquisa ainda " "existe. Você pode ver o arquivo questionnaire.log para verificar erros de " "compilação do LaTeX." #: ../sdaps/reporttex/__init__.py:107 msgid "author|Unknown" msgstr "autor|Desconhecido" #: ../sdaps/reporttex/__init__.py:138 msgid "tex language|english" msgstr "brazilian" #: ../sdaps/reporttex/__init__.py:155 #, python-format msgid "The TeX project with the report data is located at '%s'." msgstr "O projeto TeX com os dados do relatório está localizado em '%s'." #: ../sdaps/reporttex/__init__.py:158 #, python-format msgid "Running %s now twice to generate the report." msgstr "Executando %s duas vezes para gerar o relatório." #: ../sdaps/reporttex/__init__.py:168 #, python-format msgid "An occured during creation of the report. Temporary files left in '%s'." msgstr "" "Ocorreu um erro durante a criação do relatório. Os arquivos temporários " "foram deixados em '%s'." #~ msgid "%f seconds per sheet" #~ msgstr "%f segundos por folha" #~ msgid "Running upgrade routines for file format version %i" #~ msgstr "" #~ "Executando rotinas de atualização para a versão de formato de arquivo %i" #~ msgid "Create a new survey using an ODT document." #~ msgstr "Criar uma nova pesquisa usando um documento ODT." #~ msgid "" #~ "Create a new surevey from an ODT document. The PDF export\n" #~ " of the file needs to be specified at the same time. SDAPS will " #~ "import\n" #~ " metadata (properties) and the title from the ODT document." #~ msgstr "" #~ "Cria uma nova pesquisa de um documento ODT. O arquivo exportado em PDF\n" #~ " precisa ser especificado ao mesmo tempo. O SDAPS importará os\n" #~ " metadados (propriedades) e o título do documento ODT." #~ msgid "The ODT Document" #~ msgstr "O documento ODT" #~ msgid "PDF export of the ODT document" #~ msgstr "Arquivo PDF exportado a partir do documento ODT" #~ msgid "Enable printing of the survey ID (default)." #~ msgstr "Ativar a impressão do ID da pesquisa (padrão)." #~ msgid "Disable printing of the survey ID." #~ msgstr "Desativar a impressão do ID da pesquisa." #~ msgid "Enable printing of the questionnaire ID." #~ msgstr "Ativar a impressão do ID do questionário." #~ msgid "Disable printing of the questionnaire ID (default)." #~ msgstr "Desativar a impressão do ID do questionário (padrão)." #~ msgid "" #~ "Set an additional global ID for tracking. This can can only be used in " #~ "the \"code128\" style." #~ msgstr "" #~ "Definir um ID Global adicional para monitoramento. Isto só pode ser " #~ "utilizado no estilo \"code128\"." #~ msgid "" #~ "The stamping style to use. Should be either \"classic\" or \"code128\". " #~ "Use \"code128\" for more features." #~ msgstr "" #~ "O estilo que é usado para estampar. Deve ser \"classic\" ou \"code128\". " #~ "Use \"code128\" para mais recursos." #~ msgid "The mode to use when detecting checkboxes." #~ msgstr "Modo de detecção das caixas de seleção." #~ msgid "" #~ "Use duplex mode (ie. only print the IDs on the back side). Requires a " #~ "mulitple of two pages." #~ msgstr "" #~ "Use o modo duplex (ou seja, só imprimir as identificações na parte de " #~ "trás). Requer um múltiplo de duas páginas." #~ msgid "" #~ "Use simplex mode. IDs are printed on each page. You need a simplex scan " #~ "currently!" #~ msgstr "" #~ "Use o modo simplex. IDs são impressos em cada página. Você precisa de uma " #~ "verificação simplex atualmente!" #~ msgid "" #~ "Unknown file type (%s). questionnaire_odt should be application/vnd.oasis." #~ "opendocument.text." #~ msgstr "" #~ "Tipo de arquivo desconhecido (%s). O questionnaire_odt deve ser do tipo " #~ "application/vnd.oasis.opendocument.text." #~ msgid "Unknown file type (%s). questionnaire_pdf should be application/pdf." #~ msgstr "" #~ "Tipo de arquivo desconhecido (%s). O questionnaire_pdf deve ser do tipo " #~ "application/pdf." #~ msgid "" #~ "Caught an Exception while parsing the ODT file. The current state is:" #~ msgstr "Houve uma exceção ao analisar o arquivo ODT. O estado atual é:" #~ msgid "" #~ "If the dependencies for the \"annotate\" command are installed, then an " #~ "annotated version will be created next to the original PDF file." #~ msgstr "" #~ "Se as dependências para o comando \"annotate\" estão instaladas, uma " #~ "versão anotada será criada junto ao arquivo PDF original." #~ msgid "" #~ "Warning: Ignoring a box (page: %i, x: %.1f, y: %.1f, width: %.1f, height: " #~ "%.1f)." #~ msgstr "" #~ "Aviso: Ignorando uma caixa (página: %i, x: %.1f, y: %.1f, largura: %.1f, " #~ "altura: %.1f)." #~ msgid "Survey-ID: %i" #~ msgstr "ID da Pesquisa: %i" #~ msgid "Questionnaire-ID: %i" #~ msgstr "ID do Questionário: %i" #, fuzzy #~ msgid "You need to have either PDFtk or pyPdf installed. PDFtk is faster." #~ msgstr "" #~ "Você precisa ter o pdftk ou o pyPdf instalado. pdftk é o método mais " #~ "rápido." #~ msgid "Creating stamp PDF for %i sheet" #~ msgid_plural "Creating stamp PDF for %i sheets" #~ msgstr[0] "Criando estampa PDF para %i folha" #~ msgstr[1] "Criando estampa PDF para %i folhas" #~ msgid "%i sheet; %f seconds per sheet" #~ msgid_plural "%i sheet; %f seconds per sheet" #~ msgstr[0] "%i folha; %f segundos por folha" #~ msgstr[1] "%i folhas; %f segundos por folha" #, fuzzy #~ msgid "Marking using PDFtk" #~ msgstr "Estampando com pdftk" #, fuzzy #~ msgid "PDFtk: Overlaying the original PDF with the markings." #~ msgstr "pdftk: Sobrepondo o PDF original com as marcas." #, fuzzy #~ msgid "PDFtk: Splitting out page %d of each stack." #~ msgid_plural "PDFtk: Splitting out page %d of each stack." #~ msgstr[0] "pdftk: Extraindo a página %d de cada folha." #~ msgstr[1] "pdftk: Extraindo a página %d de cada folha." #, fuzzy #~ msgid "PDFtk: Splitting the questionnaire for marking." #~ msgstr "pdftk: Dividindo o questionário para marca d'água." #, fuzzy #~ msgid "PDFtk: Marking page %d of all stacks." #~ msgid_plural "PDFtk: Marking page %d of all stacks." #~ msgstr[0] "pdftk: Criando marca d'água na página %d de todas as folhas." #~ msgstr[1] "pdftk: Criando marca d'água na página %d de todas as folhas." #~ msgid "pdftk: Assembling everything into the final PDF." #~ msgstr "pdftk: Montando tudo no PDF final." #, fuzzy #~ msgid "Marking using pyPdf. For faster marking, install PDFtk." #~ msgstr "" #~ "Estampando com pyPdf. Para estampar mais rapidamente, instale o pdftk." sdaps-1.9.8/po/ro.po0000644000175000000660000006472613410742232015012 0ustar benjaminlock00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:10+0100\n" "PO-Revision-Date: 2018-10-04 13:52+0000\n" "Last-Translator: vgheo \n" "Language-Team: Romanian \n" "Language: ro\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < " "20)) ? 1 : 2;\n" "X-Generator: Weblate 3.2-dev\n" #: ../sdaps/script.py:41 msgid "SDAPS -- Paper based survey tool." msgstr "SDAPS - Utilitar pentru sondaje suport fizic" #: ../sdaps/script.py:45 msgid "command list|Commands:" msgstr "listă comenzi|Comenzi:" #: ../sdaps/script.py:50 msgid "project directory|The SDAPS project." msgstr "director proiect|Proiectul SDAPS." #: ../sdaps/add/__init__.py:55 #, python-format msgid "" "Invalid input file %s. You need to specify a (multipage) monochrome TIFF as " "input." msgstr "" "Fișier de intrare invalid : \"%s\". Trebuie să specificați ca intrare un " "fișier TIFF (multi-pagină) monocrom." #: ../sdaps/add/__init__.py:67 #, python-format msgid "" "Not adding %s because it has a wrong page count (needs to be a mulitple of " "%i)." msgstr "" "\"%s\" nu a fost adăugat deoarece are un număr incorect de pagini (trebuie " "să fie multiplu de %i)." #: ../sdaps/boxgallery/__init__.py:108 #, python-format msgid "Rendering boxgallery for metric \"%s\"." msgstr "Randăm boxgallery pentru metrica \"%s\"." #: ../sdaps/log.py:37 msgid "Warning: " msgstr "Avertizare: " #: ../sdaps/log.py:41 msgid "Error: " msgstr "Eroare: " #: ../sdaps/cmdline/add.py:31 msgid "Add scanned questionnaires to the survey." msgstr "Adaugă chestionarul scanat la sondaj" #: ../sdaps/cmdline/add.py:32 msgid "" "This command is used to add scanned images to the survey.\n" " The image data needs to be a (multipage) 300dpi monochrome TIFF file. " "You\n" " may choose not to copy the data into the project directory. In that " "case\n" " the data will be referenced using a relative path." msgstr "" "Această comandă este folosită pentru a adăuga imagini scanate la sondaj.\n" " Imaginile trebuie să fie fișiere TIFF monocrom (multi-pagină) 300dpi.\n" " Puteți alege să nu copiați imaginile în directorul proiectului. In acest " "caz\n" " fișierele cu imagini vor fi referențiate folosind o cale relativă." #: ../sdaps/cmdline/add.py:38 msgid "Convert given files and add the result." msgstr "Convertește fișierele date și adaugă rezultatul." #: ../sdaps/cmdline/add.py:43 msgid "" "Do a 3D-transformation after finding the corner marks. If the\n" " corner marks are not found then the image will be added as-is." msgstr "" "Aplică o transformare 3D după localizarea marcajelor de colț. Dacă\n" " marcajele de colț nu sunt localizate, imaginea va fi adăugată fără \n" " modificări." #: ../sdaps/cmdline/add.py:49 msgid "" "Force adding the images even if the page count is wrong (only use if you " "know what you are doing)." msgstr "" "Forțează adăugarea imaginilor chiar dacă numărul de pagini este greșit (de " "folosit numai dacă știți ce faceți)." #: ../sdaps/cmdline/add.py:53 msgid "Copy the files into the directory (default)." msgstr "Copiază fișierele în director (implicit)." #: ../sdaps/cmdline/add.py:58 msgid "Do not copy the files into the directory." msgstr "Nu copia fișierele în director." #: ../sdaps/cmdline/add.py:62 msgid "" "Images contain a duplex scan of a simplex questionnaire (default: simplex " "scan)." msgstr "" "Imaginile conțin a scanare duplex a unui chestionar simplex (implicit : " "scanare simplex)." #: ../sdaps/cmdline/add.py:68 ../sdaps/cmdline/convert.py:48 msgid "A number of TIFF image files." msgstr "Un număr de fișiere cu imagini TIFF." #: ../sdaps/cmdline/add.py:94 msgid "The --no-copy option is not compatible with --convert!" msgstr "Opțiunea --no-copy nu este compatibilă cu --convert !" #: ../sdaps/cmdline/add.py:103 msgid "Converting input files into a single temporary file." msgstr "Se convertesc fișierele de intrare într-un singur fișier temporar." #: ../sdaps/cmdline/add.py:115 msgid "" "The page count of the created temporary file does not work with this survey." msgstr "" "Numărul de pagini al fișierului creat temporar nu este potrivit pentru acest " "sondaj." #: ../sdaps/cmdline/add.py:120 msgid "Running the conversion failed." msgstr "Conversia a eșuat." #: ../sdaps/cmdline/add.py:126 #, python-format msgid "Processing %s" msgstr "Se procesează %s" #: ../sdaps/cmdline/add.py:130 ../sdaps/reset/__init__.py:33 msgid "Done" msgstr "Gata" #: ../sdaps/cmdline/annotate.py:28 msgid "Annotate the questionnaire and show the recognized positions." msgstr "Adnotați chestionarul și arătați pozițiile recunoscute." #: ../sdaps/cmdline/annotate.py:29 msgid "" "This command is mainly a debug utility. It creates an\n" " annotated version of the questionnaire, with the information that SDAPS\n" " knows about it overlayed on top." msgstr "" #: ../sdaps/cmdline/boxgallery.py:31 msgid "Create PDFs with boxes sorted by the detection heuristics." msgstr "" #: ../sdaps/cmdline/boxgallery.py:32 msgid "" "SDAPS uses multiple heuristics to detect determine the\n" " state of checkboxes. There is a list for each heuristic giving the " "expected\n" " state and the quality of the value (see defs.py). Using this command a " "PDF\n" " will be created for each of the heuristics so that one can adjust the\n" " values." msgstr "" #: ../sdaps/cmdline/boxgallery.py:40 msgid "" "Reruns part of the recognition process and retrieves debug images from this " "step." msgstr "" #: ../sdaps/cmdline/convert.py:30 msgid "Convert a set of images to the correct image format." msgstr "" #: ../sdaps/cmdline/convert.py:31 msgid "" "This command can be used if you scanned files in something\n" " other than the expected monochrome TIFF mode. All given files will\n" " be loaded, converted to monochrome and stored in a multipage 1bpp\n" " TIFF file. Optionally, you can select \"3D transformation\"\\ ,which " "may facilitate\n" " working with photos of questionnaires instead of scans." msgstr "" #: ../sdaps/cmdline/convert.py:38 msgid "" "Do a 3D-transformation after finding the corner marks.\n" " If they are not found, the image will be processed as-is." msgstr "" #: ../sdaps/cmdline/convert.py:44 msgid "The location of the output file." msgstr "" #: ../sdaps/cmdline/convert.py:57 msgid "No output filename specified!" msgstr "" #: ../sdaps/cmdline/cover.py:27 msgid "Create a cover for the questionnaires." msgstr "" #: ../sdaps/cmdline/cover.py:28 msgid "" "This command creates a cover page for questionnaires. All\n" " the metadata of the survey will be printed on the page." msgstr "" #: ../sdaps/cmdline/cover.py:31 #, python-format msgid "Filename to store the data to (default: cover_%%i.pdf)" msgstr "" #: ../sdaps/cmdline/csvdata.py:34 msgid "Import or export data to/from CSV files." msgstr "" #: ../sdaps/cmdline/csvdata.py:35 msgid "" "Import or export data to/from a CSV file. The first line\n" " is a header which defines questionnaire_id and global_id, and a column\n" " for each checkbox and textfield. Note that the import is currently very\n" " limited, as you need to specifiy the questionnaire ID to select the " "sheet\n" " which should be updated." msgstr "" #: ../sdaps/cmdline/csvdata.py:44 msgid "Export data to CSV file." msgstr "" #: ../sdaps/cmdline/csvdata.py:46 #, python-format msgid "Filename to store the data to (default: data_%%i.csv)" msgstr "" #: ../sdaps/cmdline/csvdata.py:48 msgid "The delimiter used in the CSV file (default ',')" msgstr "" #: ../sdaps/cmdline/csvdata.py:52 ../sdaps/cmdline/report.py:31 #: ../sdaps/cmdline/reporttex.py:52 msgid "Filter to only export a partial dataset." msgstr "" #: ../sdaps/cmdline/csvdata.py:54 msgid "Export images of freeform fields." msgstr "" #: ../sdaps/cmdline/csvdata.py:60 msgid "Export an image for each question that includes all boxes." msgstr "" #: ../sdaps/cmdline/csvdata.py:66 msgid "Export the recognition quality for each checkbox." msgstr "" #: ../sdaps/cmdline/csvdata.py:74 msgid "Import data to from a CSV file." msgstr "" #: ../sdaps/cmdline/csvdata.py:76 msgid "The file to import." msgstr "" #: ../sdaps/cmdline/gui.py:28 msgid "Launch a GUI. You can view and alter the (recognized) answers with it." msgstr "" #: ../sdaps/cmdline/gui.py:29 msgid "" "This command launches a graphical user interface that can\n" " be used to correct answers. You need to run \"recognize\" before using " "it.\n" " " msgstr "" #: ../sdaps/cmdline/gui.py:34 msgid "Filter to only show a partial dataset." msgstr "" #: ../sdaps/cmdline/ids.py:29 msgid "Export and import questionnaire IDs." msgstr "" #: ../sdaps/cmdline/ids.py:30 msgid "" "This command can be used to import and export questionnaire\n" " IDs. It only makes sense in projects where such an ID is printed on the\n" " questionnaire. Note that you can also add IDs by using the stamp " "command,\n" " which will give you the PDF at the same time." msgstr "" #: ../sdaps/cmdline/ids.py:35 #, python-format msgid "Filename to store the data to (default: ids_%%i)" msgstr "" #: ../sdaps/cmdline/ids.py:38 msgid "Add IDs to the internal list from the specified file." msgstr "" #: ../sdaps/cmdline/info.py:28 msgid "Display and modify metadata of project." msgstr "" #: ../sdaps/cmdline/info.py:29 msgid "" "This command lets you modify the metadata of the SDAPS\n" " project. You can modify, add and remove arbitrary keys that will be " "printed\n" " on the report. The only key that always exist is \"title\".\n" " If no key is given then a list of defined keys is printed." msgstr "" #: ../sdaps/cmdline/info.py:36 msgid "Delete the key and value pair." msgstr "" #: ../sdaps/cmdline/info.py:40 msgid "The key to display or modify." msgstr "" #: ../sdaps/cmdline/info.py:44 msgid "Set the given key to this value." msgstr "" #: ../sdaps/cmdline/info.py:69 msgid "Existing fields:\n" msgstr "" #: ../sdaps/cmdline/recognize.py:28 msgid "Run the optical mark recognition." msgstr "" #: ../sdaps/cmdline/recognize.py:29 msgid "" "Iterates over all images and runs the optical mark\n" " recognition. It will reevaluate sheets even if \"recognize\" has " "already\n" " run or manual changes were made." msgstr "" #: ../sdaps/cmdline/recognize.py:34 msgid "" "Only identify the page properties, but don't recognize the checkbox states." msgstr "" #: ../sdaps/cmdline/recognize.py:39 msgid "" "Rerun the recognition for all pages. The default is to skip all pages that " "were recognized or verified already." msgstr "" #: ../sdaps/cmdline/reorder.py:26 msgid "Reorder pages according to questionnaire ID." msgstr "" #: ../sdaps/cmdline/reorder.py:27 msgid "" "This command reorders all pages according to the already\n" " recognized questionnaire ID. To use it add all the files to the " "project,\n" " then run a partial recognition using \"recognize --identify\". After " "this\n" " you have to run this command to reorder the data for the real " "recognition.\n" " " msgstr "" #: ../sdaps/cmdline/report.py:26 msgid "Create a PDF report." msgstr "" #: ../sdaps/cmdline/report.py:27 msgid "" "This command creates a PDF report using reportlab that\n" " contains statistics and if selected the freeform fields." msgstr "" #: ../sdaps/cmdline/report.py:33 msgid "Create a filtered report for every checkbox." msgstr "" #: ../sdaps/cmdline/report.py:36 msgid "Short format (without freeform text fields)." msgstr "" #: ../sdaps/cmdline/report.py:41 msgid "Detailed output. (default)" msgstr "" #: ../sdaps/cmdline/report.py:47 ../sdaps/cmdline/reporttex.py:30 msgid "" "Do not include original images in the report. This is useful if there are " "privacy concerns." msgstr "" #: ../sdaps/cmdline/report.py:52 ../sdaps/cmdline/reporttex.py:35 msgid "Do not use substitutions instead of images." msgstr "" #: ../sdaps/cmdline/report.py:58 ../sdaps/cmdline/reporttex.py:46 msgid "The paper size used for the output (default: locale dependent)" msgstr "" #: ../sdaps/cmdline/report.py:61 ../sdaps/cmdline/reporttex.py:49 #, python-format msgid "Filename to store the data to (default: report_%%i.pdf)" msgstr "" #: ../sdaps/cmdline/reporttex.py:26 msgid "Create a PDF report using LaTeX." msgstr "" #: ../sdaps/cmdline/reporttex.py:27 msgid "" "This command creates a PDF report using LaTeX that\n" " contains statistics and freeform fields." msgstr "" #: ../sdaps/cmdline/reporttex.py:41 msgid "Save the generated TeX files instead of the final PDF." msgstr "" #: ../sdaps/cmdline/reset.py:26 msgid "Reset project into original state" msgstr "" #: ../sdaps/cmdline/reset.py:27 msgid "" "This command does a full reset of the project. All data\n" " will be discarded and only the empty project is left.\n" " " msgstr "" #: ../sdaps/cmdline/setup.py:27 msgid "Create a new survey using a LaTeX document." msgstr "" #: ../sdaps/cmdline/setup.py:28 msgid "" "Create a new survey from a LaTeX document. You need to\n" " be using the SDAPS class. All the metadata and options for the project\n" " can be set inside the LaTeX document." msgstr "" #: ../sdaps/cmdline/setup.py:33 msgid "The LaTeX Document" msgstr "" #: ../sdaps/cmdline/setup.py:35 msgid "" "Additional files that are required by the LaTeX document and need to be " "copied into the project directory." msgstr "" #: ../sdaps/cmdline/setup.py:39 msgid "Additional questions that are not part of the questionnaire." msgstr "" #: ../sdaps/cmdline/stamp.py:26 msgid "Add marks for automatic processing." msgstr "" #: ../sdaps/cmdline/stamp.py:27 msgid "" "This command creates the printable document. Depending on\n" " the projects setting you are required to specifiy a source for " "questionnaire\n" " IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:33 msgid "" "If using questionnaire IDs, create N questionnaires with randomized IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:36 msgid "" "If using questionnaire IDs, create questionnaires from the IDs read from the " "specified file." msgstr "" #: ../sdaps/cmdline/stamp.py:39 msgid "If using questionnaire IDs, create questionnaires for all stored IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:42 #, python-format msgid "Filename to store the data to (default: stamp_%%i.pdf)" msgstr "" #: ../sdaps/convert/__init__.py:37 #, python-format msgid "Could not apply 3D-transformation to image '%s', page %i!" msgstr "" #: ../sdaps/cover/__init__.py:40 msgid "SDAPS questionnaire" msgstr "" #: ../sdaps/csvdata/buddies.py:77 #, python-format msgid "Not importing unknown questionnaire ID \"%s\"" msgstr "" #: ../sdaps/gui/__init__.py:59 msgid "" "The survey does not have any images! Please add images (and run recognize) " "before using the GUI." msgstr "" #: ../sdaps/gui/__init__.py:211 msgid "Page|Invalid" msgstr "" #: ../sdaps/gui/__init__.py:214 #, python-format msgid "Page %i" msgid_plural "Page %i" msgstr[0] "" msgstr[1] "" #: ../sdaps/gui/__init__.py:256 msgid "Copyright © 2007-2014 The SDAPS Authors" msgstr "" #: ../sdaps/gui/__init__.py:258 msgid "Scripts for data acquisition with paper based surveys" msgstr "" #: ../sdaps/gui/__init__.py:259 msgid "http://sdaps.org" msgstr "" #: ../sdaps/gui/__init__.py:260 msgid "translator-credits" msgstr "" #: ../sdaps/gui/__init__.py:305 #, python-format msgid " of %i" msgstr "" #: ../sdaps/gui/__init__.py:306 #, python-format msgid "Recognition Quality: %.2f" msgstr "" #: ../sdaps/gui/__init__.py:322 msgid "" "You have reached the first page of the survey. Would you like to go to the " "last page?" msgstr "" #: ../sdaps/gui/__init__.py:324 msgid "Go to last page" msgstr "" #: ../sdaps/gui/__init__.py:346 msgid "" "You have reached the last page of the survey. Would you like to go to the " "first page?" msgstr "" #: ../sdaps/gui/__init__.py:348 msgid "Go to first page" msgstr "" #: ../sdaps/gui/__init__.py:457 msgid "Close without saving" msgstr "" #: ../sdaps/gui/__init__.py:461 msgid "" "Save the project before closing?\n" "\n" "If you do not save you may loose data." msgstr "" #: ../sdaps/gui/main_window.ui.h:1 msgid "Forward" msgstr "" #: ../sdaps/gui/main_window.ui.h:2 msgid "Previous" msgstr "" #: ../sdaps/gui/main_window.ui.h:3 msgid "Zoom In" msgstr "" #: ../sdaps/gui/main_window.ui.h:4 msgid "Zoom Out" msgstr "" #: ../sdaps/gui/main_window.ui.h:5 msgid "SDAPS" msgstr "" #: ../sdaps/gui/main_window.ui.h:6 msgid "_File" msgstr "" #: ../sdaps/gui/main_window.ui.h:7 msgid "_View" msgstr "" #: ../sdaps/gui/main_window.ui.h:8 msgid "_Help" msgstr "" #: ../sdaps/gui/main_window.ui.h:9 msgid "Page Rotated" msgstr "" #: ../sdaps/gui/main_window.ui.h:10 msgid "Sort by Quality" msgstr "" #: ../sdaps/gui/main_window.ui.h:11 msgid "label" msgstr "" #: ../sdaps/gui/widget_buddies.py:56 msgid "Global Properties" msgstr "" #: ../sdaps/gui/widget_buddies.py:60 msgid "Sheet valid" msgstr "" #: ../sdaps/gui/widget_buddies.py:61 msgid "Sheet Verified" msgstr "" #: ../sdaps/gui/widget_buddies.py:62 msgid "Page Verified" msgstr "" #: ../sdaps/gui/widget_buddies.py:63 msgid "Empty" msgstr "" #: ../sdaps/gui/widget_buddies.py:75 ../sdaps/gui/widget_buddies.py:105 msgid "Questionnaire ID: " msgstr "" #: ../sdaps/image/__init__.py:47 msgid "" "It appears you have not build the C extension. Please run \"./setup.py build" "\" in the toplevel directory." msgstr "" #: ../sdaps/utils/latex.py:29 msgid "" "The latex character map is missing! Please build it using the supplied tool " "(create-latexmap.py)." msgstr "" #: ../sdaps/utils/latex.py:69 msgid "" "Generated string for LaTeX contains unicode characters. This may not work " "correctly and could mean the LaTeX character map needs to be updated." msgstr "" #: ../sdaps/utils/opencv.py:35 msgid "Cannot convert PDF files as poppler is not installed or usable!" msgstr "" #: ../sdaps/utils/opencv.py:44 msgid "File does not exist" msgstr "" #. The old code used to first filter, and then run; but that is #. a bit ineffective in a way #: ../sdaps/model/survey.py:386 #, python-format msgid "%i sheet" msgid_plural "%i sheets" msgstr[0] "" msgstr[1] "" #: ../sdaps/model/survey.py:402 #, python-format msgid "Processed %i of %i sheets, took %f seconds" msgstr "" #: ../sdaps/model/survey.py:449 msgid "" "A questionnaire that is printed in duplex needs an even amount of pages!" msgstr "" #: ../sdaps/model/survey.py:453 msgid "" "The 'classic' style only supports a maximum of six pages! Use the 'code128' " "style if you require more pages." msgstr "" #: ../sdaps/model/survey.py:466 msgid "IDs need to be integers in \"classic\" style!" msgstr "" #: ../sdaps/model/survey.py:472 #, python-format msgid "Invalid character %s in questionnaire ID \"%s\" in \"code128\" style!" msgstr "" #: ../sdaps/model/survey.py:476 msgid "" "SDAPS cannot draw a questionnaire ID with the \"custom\" style. Do this " "yourself somehow!" msgstr "" #. in simplex mode every page will have a matrix; it might be a None #. matrix though #: ../sdaps/recognize/buddies.py:71 #, python-format msgid "%s, %i: Matrix not recognized." msgstr "" #: ../sdaps/recognize/buddies.py:80 #, python-format msgid "%s, %i: Rotation not found." msgstr "" #. Copy the rotation over (if required) and print warning if the rotation is unknown #: ../sdaps/recognize/buddies.py:84 #, python-format msgid "Neither %s, %i or %s, %i has a known rotation!" msgstr "" #: ../sdaps/recognize/buddies.py:96 #, python-format msgid "%s, %i: Matrix not recognized (again)." msgstr "" #: ../sdaps/recognize/buddies.py:110 #, python-format msgid "%s, %i: Could not get page number." msgstr "" #. Whoa, that should not happen. #: ../sdaps/recognize/buddies.py:130 #, python-format msgid "Neither %s, %i or %s, %i has a known page number!" msgstr "" #. We don't touch the ignore flag in this case #. Simply print a message as this should *never* happen #: ../sdaps/recognize/buddies.py:141 #, python-format msgid "" "Got a simplex document where two adjacent pages had a known page number. " "This should never happen as even simplex scans are converted to duplex by " "inserting dummy pages. Maybe you did a simplex scan but added it in duplex " "mode? The pages in question are %s, %i and %s, %i." msgstr "" #: ../sdaps/recognize/buddies.py:158 #, python-format msgid "Images %s, %i and %s, %i do not have consecutive page numbers!" msgstr "" #: ../sdaps/recognize/buddies.py:174 #, python-format msgid "No page number for page %s, %i exists." msgstr "" #: ../sdaps/recognize/buddies.py:179 #, python-format msgid "Page number for page %s, %i already used by another image." msgstr "" #: ../sdaps/recognize/buddies.py:185 #, python-format msgid "Page number %i for page %s, %i is out of range." msgstr "" #: ../sdaps/recognize/buddies.py:202 #, python-format msgid "%s, %i: Could not read survey ID, but should be able to." msgstr "" #: ../sdaps/recognize/buddies.py:206 #, python-format msgid "Could not read survey ID of either %s, %i or %s, %i!" msgstr "" #. Broken survey ID ... #: ../sdaps/recognize/buddies.py:213 #, python-format msgid "Got a wrong survey ID (%s, %i)! It is %s, but should be %i." msgstr "" #: ../sdaps/recognize/buddies.py:235 #, python-format msgid "%s, %i: Could not read questionnaire ID, but should be able to." msgstr "" #: ../sdaps/recognize/buddies.py:241 #, python-format msgid "Could not read questionnaire ID of either %s, %i or %s, %i!" msgstr "" #: ../sdaps/recognize/buddies.py:271 msgid "" "Got different IDs on different pages for at least one sheet! Do *NOT* try to " "use filters with this survey! You have to run a \"reorder\" step for this to " "work properly!" msgstr "" #: ../sdaps/recognize/buddies.py:326 msgid "No style buddy loaded. This needs to be done for the \"custom\" style!" msgstr "" #: ../sdaps/report/answers.py:188 #, python-format msgid "Answers: %i" msgstr "" #: ../sdaps/report/answers.py:190 #, python-format msgid "Mean: %.2f" msgstr "" #: ../sdaps/report/answers.py:192 #, python-format msgid "Standard Deviation: %.2f" msgstr "" #: ../sdaps/report/__init__.py:75 ../sdaps/reporttex/__init__.py:140 msgid "Turned in Questionnaires" msgstr "" #: ../sdaps/report/__init__.py:92 ../sdaps/reporttex/__init__.py:139 msgid "sdaps report" msgstr "" #: ../sdaps/reset/__init__.py:29 msgid "Removing stored data..." msgstr "" #: ../sdaps/setup/buddies.py:62 #, python-format msgid "Head %(l0)i got no title." msgstr "" #: ../sdaps/setup/buddies.py:74 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no question." msgstr "" #: ../sdaps/setup/buddies.py:114 #, python-format msgid "Error in question \"%s\"" msgstr "" #: ../sdaps/setup/buddies.py:118 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no boxes." msgstr "" #: ../sdaps/setup/buddies.py:167 #, python-format msgid "%(class)s %(l0)i.%(l1)i lower box out of range." msgstr "" #: ../sdaps/setup/buddies.py:172 #, python-format msgid "%(class)s %(l0)i.%(l1)i upper box out of range." msgstr "" #: ../sdaps/setup/buddies.py:177 #, python-format msgid "%(class)s %(l0)i.%(l1)i lower box not before upper box." msgstr "" #: ../sdaps/setup/buddies.py:213 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly two answers." msgstr "" #: ../sdaps/setup/buddies.py:234 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly one box." msgstr "" #: ../sdaps/stamp/__init__.py:38 msgid "" "You may not specify the number of sheets for this survey. All questionnaires " "will be identical as the survey has been configured to not use questionnaire " "IDs for each sheet." msgstr "" #: ../sdaps/stamp/__init__.py:76 msgid "" "This survey has been configured to use questionnaire IDs. Each questionnaire " "will be unique. You need to use on of the options to add new IDs or use the " "existing ones." msgstr "" #: ../sdaps/stamp/latex.py:18 msgid "" "There should be no need to stamp a SDAPS Project that uses LaTeX and does " "not have different questionnaire IDs printed on each sheet.\n" "I am going to do so anyways." msgstr "" #: ../sdaps/stamp/latex.py:26 #, python-format msgid "Running %s now twice to generate the stamped questionnaire." msgstr "" #: ../sdaps/stamp/latex.py:30 ../sdaps/setuptex/__init__.py:107 #: ../sdaps/setuptex/__init__.py:148 ../sdaps/reporttex/__init__.py:162 #, python-format msgid "Error running \"%s\" to compile the LaTeX file." msgstr "" #: ../sdaps/stamp/latex.py:36 #, python-format msgid "" "An error occured during creation of the report. Temporary files left in '%s'." msgstr "" #: ../sdaps/setuptex/__init__.py:46 msgid "The survey directory already exists." msgstr "" #: ../sdaps/setuptex/__init__.py:51 #, python-format msgid "Unknown file type (%s). questionnaire_tex should be of type text/x-tex." msgstr "" #: ../sdaps/setuptex/__init__.py:52 msgid "Will keep going, but expect failure!" msgstr "" #: ../sdaps/setuptex/__init__.py:57 #, python-format msgid "Unknown file type (%s). additionalqobjects should be text/plain." msgstr "" #: ../sdaps/setuptex/__init__.py:103 ../sdaps/setuptex/__init__.py:143 #, python-format msgid "Running %s now twice to generate the questionnaire." msgstr "" #: ../sdaps/setuptex/__init__.py:122 msgid "Caught an Exception while parsing the SDAPS file. The current state is:" msgstr "" #: ../sdaps/setuptex/__init__.py:136 msgid "" "Some combination of options and project properties do not work. Aborted " "Setup." msgstr "" "Combinație de opțiuni și proprietăți ale proiectului incompatibile. Setup " "abandonat." #: ../sdaps/setuptex/__init__.py:162 msgid "" "An error occured in the setup routine. The survey directory still exists. " "You can for example check the questionnaire.log file for LaTeX compile " "errors." msgstr "" "A apărut o eroare în procedura de setup. Directorul sondajului încă există. " "Puteți verifica erorile de compilare LaTeX în fișierul questionnaire.log." #: ../sdaps/reporttex/__init__.py:107 msgid "author|Unknown" msgstr "autor|Necunoscut" #: ../sdaps/reporttex/__init__.py:138 msgid "tex language|english" msgstr "limbaj tex|română" #: ../sdaps/reporttex/__init__.py:155 #, python-format msgid "The TeX project with the report data is located at '%s'." msgstr "Proiectul TeX cu datele raportului este disponibil la '%s'." #: ../sdaps/reporttex/__init__.py:158 #, python-format msgid "Running %s now twice to generate the report." msgstr "" #: ../sdaps/reporttex/__init__.py:168 #, python-format msgid "An occured during creation of the report. Temporary files left in '%s'." msgstr "" sdaps-1.9.8/po/sdaps.pot0000644000175000000660000006157113611127123015662 0ustar benjaminlock00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-01-19 20:30+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #: ../sdaps/script.py:42 msgid "SDAPS -- Paper based survey tool." msgstr "" #: ../sdaps/script.py:47 msgid "Display version and exit" msgstr "" #. Set required as an attribute rather than kwarg so that it works with python <3.7 #: ../sdaps/script.py:52 msgid "command list|Commands:" msgstr "" #: ../sdaps/script.py:61 msgid "project directory|The SDAPS project." msgstr "" #: ../sdaps/add/__init__.py:55 #, python-format msgid "" "Invalid input file %s. You need to specify a (multipage) monochrome TIFF as " "input." msgstr "" #: ../sdaps/add/__init__.py:67 #, python-format msgid "" "Not adding %s because it has a wrong page count (needs to be a mulitple of " "%i)." msgstr "" #: ../sdaps/boxgallery/__init__.py:108 #, python-format msgid "Rendering boxgallery for metric \"%s\"." msgstr "" #: ../sdaps/log.py:37 msgid "Warning: " msgstr "" #: ../sdaps/log.py:41 msgid "Error: " msgstr "" #: ../sdaps/cmdline/add.py:31 msgid "Add scanned questionnaires to the survey." msgstr "" #: ../sdaps/cmdline/add.py:32 msgid "" "This command is used to add scanned images to the survey.\n" " The image data needs to be a (multipage) 300dpi monochrome TIFF file. " "You\n" " may choose not to copy the data into the project directory. In that " "case\n" " the data will be referenced using a relative path." msgstr "" #: ../sdaps/cmdline/add.py:38 msgid "Convert given files and add the result." msgstr "" #: ../sdaps/cmdline/add.py:43 msgid "" "Do a 3D-transformation after finding the corner marks. If the\n" " corner marks are not found then the image will be added as-is." msgstr "" #: ../sdaps/cmdline/add.py:49 msgid "" "Force adding the images even if the page count is wrong (only use if you " "know what you are doing)." msgstr "" #: ../sdaps/cmdline/add.py:53 msgid "Copy the files into the directory (default)." msgstr "" #: ../sdaps/cmdline/add.py:58 msgid "Do not copy the files into the directory." msgstr "" #: ../sdaps/cmdline/add.py:62 msgid "" "Images contain a duplex scan of a simplex questionnaire (default: simplex " "scan)." msgstr "" #: ../sdaps/cmdline/add.py:68 ../sdaps/cmdline/convert.py:48 msgid "A number of TIFF image files." msgstr "" #: ../sdaps/cmdline/add.py:94 msgid "The --no-copy option is not compatible with --convert!" msgstr "" #: ../sdaps/cmdline/add.py:103 msgid "Converting input files into a single temporary file." msgstr "" #: ../sdaps/cmdline/add.py:115 msgid "" "The page count of the created temporary file does not work with this survey." msgstr "" #: ../sdaps/cmdline/add.py:120 msgid "Running the conversion failed." msgstr "" #: ../sdaps/cmdline/add.py:126 #, python-format msgid "Processing %s" msgstr "" #: ../sdaps/cmdline/add.py:130 ../sdaps/reset/__init__.py:33 msgid "Done" msgstr "" #: ../sdaps/cmdline/annotate.py:28 msgid "Annotate the questionnaire and show the recognized positions." msgstr "" #: ../sdaps/cmdline/annotate.py:29 msgid "" "This command is mainly a debug utility. It creates an\n" " annotated version of the questionnaire, with the information that SDAPS\n" " knows about it overlayed on top." msgstr "" #: ../sdaps/cmdline/boxgallery.py:31 msgid "Create PDFs with boxes sorted by the detection heuristics." msgstr "" #: ../sdaps/cmdline/boxgallery.py:32 msgid "" "SDAPS uses multiple heuristics to detect determine the\n" " state of checkboxes. There is a list for each heuristic giving the " "expected\n" " state and the quality of the value (see defs.py). Using this command a " "PDF\n" " will be created for each of the heuristics so that one can adjust the\n" " values." msgstr "" #: ../sdaps/cmdline/boxgallery.py:40 msgid "" "Reruns part of the recognition process and retrieves debug images from this " "step." msgstr "" #: ../sdaps/cmdline/convert.py:30 msgid "Convert a set of images to the correct image format." msgstr "" #: ../sdaps/cmdline/convert.py:31 msgid "" "This command can be used if you scanned files in something\n" " other than the expected monochrome TIFF mode. All given files will\n" " be loaded, converted to monochrome and stored in a multipage 1bpp\n" " TIFF file. Optionally, you can select \"3D transformation\"\\ ,which " "may facilitate\n" " working with photos of questionnaires instead of scans." msgstr "" #: ../sdaps/cmdline/convert.py:38 msgid "" "Do a 3D-transformation after finding the corner marks.\n" " If they are not found, the image will be processed as-is." msgstr "" #: ../sdaps/cmdline/convert.py:44 msgid "The location of the output file." msgstr "" #: ../sdaps/cmdline/convert.py:57 msgid "No output filename specified!" msgstr "" #: ../sdaps/cmdline/cover.py:27 msgid "Create a cover for the questionnaires." msgstr "" #: ../sdaps/cmdline/cover.py:28 msgid "" "This command creates a cover page for questionnaires. All\n" " the metadata of the survey will be printed on the page." msgstr "" #: ../sdaps/cmdline/cover.py:31 #, python-format msgid "Filename to store the data to (default: cover_%%i.pdf)" msgstr "" #: ../sdaps/cmdline/csvdata.py:34 msgid "Import or export data to/from CSV files." msgstr "" #: ../sdaps/cmdline/csvdata.py:35 msgid "" "Import or export data to/from a CSV file. The first line\n" " is a header which defines questionnaire_id and global_id, and a column\n" " for each checkbox and textfield. Note that the import is currently very\n" " limited, as you need to specifiy the questionnaire ID to select the " "sheet\n" " which should be updated." msgstr "" #: ../sdaps/cmdline/csvdata.py:46 msgid "Export data to CSV file." msgstr "" #: ../sdaps/cmdline/csvdata.py:50 #, python-format msgid "Filename to store the data to (default: data_%%i.csv)" msgstr "" #: ../sdaps/cmdline/csvdata.py:52 msgid "The delimiter used in the CSV file (default ',')" msgstr "" #: ../sdaps/cmdline/csvdata.py:56 ../sdaps/cmdline/report.py:31 #: ../sdaps/cmdline/reporttex.py:52 msgid "Filter to only export a partial dataset." msgstr "" #: ../sdaps/cmdline/csvdata.py:58 msgid "Export images of freeform fields." msgstr "" #: ../sdaps/cmdline/csvdata.py:64 msgid "Export an image for each question that includes all boxes." msgstr "" #: ../sdaps/cmdline/csvdata.py:70 msgid "Export the recognition quality for each checkbox." msgstr "" #: ../sdaps/cmdline/csvdata.py:78 msgid "Import data to from a CSV file." msgstr "" #: ../sdaps/cmdline/csvdata.py:82 msgid "The file to import." msgstr "" #: ../sdaps/cmdline/gui.py:28 msgid "Launch a GUI. You can view and alter the (recognized) answers with it." msgstr "" #: ../sdaps/cmdline/gui.py:29 msgid "" "This command launches a graphical user interface that can\n" " be used to correct answers. You need to run \"recognize\" before using " "it.\n" " " msgstr "" #: ../sdaps/cmdline/gui.py:34 msgid "Filter to only show a partial dataset." msgstr "" #: ../sdaps/cmdline/ids.py:29 msgid "Export and import questionnaire IDs." msgstr "" #: ../sdaps/cmdline/ids.py:30 msgid "" "This command can be used to import and export questionnaire\n" " IDs. It only makes sense in projects where such an ID is printed on the\n" " questionnaire. Note that you can also add IDs by using the stamp " "command,\n" " which will give you the PDF at the same time." msgstr "" #: ../sdaps/cmdline/ids.py:35 #, python-format msgid "Filename to store the data to (default: ids_%%i)" msgstr "" #: ../sdaps/cmdline/ids.py:38 msgid "Add IDs to the internal list from the specified file." msgstr "" #: ../sdaps/cmdline/info.py:28 msgid "Display and modify metadata of project." msgstr "" #: ../sdaps/cmdline/info.py:29 msgid "" "This command lets you modify the metadata of the SDAPS\n" " project. You can modify, add and remove arbitrary keys that will be " "printed\n" " on the report. The only key that always exist is \"title\".\n" " If no key is given then a list of defined keys is printed." msgstr "" #: ../sdaps/cmdline/info.py:36 msgid "Delete the key and value pair." msgstr "" #: ../sdaps/cmdline/info.py:40 msgid "The key to display or modify." msgstr "" #: ../sdaps/cmdline/info.py:44 msgid "Set the given key to this value." msgstr "" #: ../sdaps/cmdline/info.py:69 msgid "Existing fields:\n" msgstr "" #: ../sdaps/cmdline/recognize.py:28 msgid "Run the optical mark recognition." msgstr "" #: ../sdaps/cmdline/recognize.py:29 msgid "" "Iterates over all images and runs the optical mark\n" " recognition. It will reevaluate sheets even if \"recognize\" has " "already\n" " run or manual changes were made." msgstr "" #: ../sdaps/cmdline/recognize.py:34 msgid "" "Only identify the page properties, but don't recognize the checkbox states." msgstr "" #: ../sdaps/cmdline/recognize.py:39 msgid "" "Rerun the recognition for all pages. The default is to skip all pages that " "were recognized or verified already." msgstr "" #: ../sdaps/cmdline/reorder.py:26 msgid "Reorder pages according to questionnaire ID." msgstr "" #: ../sdaps/cmdline/reorder.py:27 msgid "" "This command reorders all pages according to the already\n" " recognized questionnaire ID. To use it add all the files to the " "project,\n" " then run a partial recognition using \"recognize --identify\". After " "this\n" " you have to run this command to reorder the data for the real " "recognition.\n" " " msgstr "" #: ../sdaps/cmdline/report.py:26 msgid "Create a PDF report." msgstr "" #: ../sdaps/cmdline/report.py:27 msgid "" "This command creates a PDF report using reportlab that\n" " contains statistics and if selected the freeform fields." msgstr "" #: ../sdaps/cmdline/report.py:33 msgid "Create a filtered report for every checkbox." msgstr "" #: ../sdaps/cmdline/report.py:36 msgid "Short format (without freeform text fields)." msgstr "" #: ../sdaps/cmdline/report.py:41 msgid "Detailed output. (default)" msgstr "" #: ../sdaps/cmdline/report.py:47 ../sdaps/cmdline/reporttex.py:30 msgid "" "Do not include original images in the report. This is useful if there are " "privacy concerns." msgstr "" #: ../sdaps/cmdline/report.py:52 ../sdaps/cmdline/reporttex.py:35 msgid "Do not use substitutions instead of images." msgstr "" #: ../sdaps/cmdline/report.py:58 ../sdaps/cmdline/reporttex.py:46 msgid "The paper size used for the output (default: locale dependent)" msgstr "" #: ../sdaps/cmdline/report.py:61 ../sdaps/cmdline/reporttex.py:49 #, python-format msgid "Filename to store the data to (default: report_%%i.pdf)" msgstr "" #: ../sdaps/cmdline/reporttex.py:26 msgid "Create a PDF report using LaTeX." msgstr "" #: ../sdaps/cmdline/reporttex.py:27 msgid "" "This command creates a PDF report using LaTeX that\n" " contains statistics and freeform fields." msgstr "" #: ../sdaps/cmdline/reporttex.py:41 msgid "Save the generated TeX files instead of the final PDF." msgstr "" #: ../sdaps/cmdline/reset.py:26 msgid "Reset project into original state" msgstr "" #: ../sdaps/cmdline/reset.py:27 msgid "" "This command does a full reset of the project. All data\n" " will be discarded and only the empty project is left.\n" " " msgstr "" #: ../sdaps/cmdline/setup.py:28 msgid "Create a new survey using a LaTeX document." msgstr "" #: ../sdaps/cmdline/setup.py:29 msgid "" "Create a new survey from a LaTeX document. You need to\n" " be using the SDAPS class. All the metadata and options for the project\n" " can be set inside the LaTeX document." msgstr "" #: ../sdaps/cmdline/setup.py:34 msgid "The LaTeX Document" msgstr "" #: ../sdaps/cmdline/setup.py:36 msgid "" "Additional files that are required by the LaTeX document and need to be " "copied into the project directory." msgstr "" #: ../sdaps/cmdline/setup.py:39 msgid "The engine to use to compile LaTeX documents." msgstr "" #: ../sdaps/cmdline/setup.py:43 msgid "Additional questions that are not part of the questionnaire." msgstr "" #: ../sdaps/cmdline/stamp.py:26 msgid "Add marks for automatic processing." msgstr "" #: ../sdaps/cmdline/stamp.py:27 msgid "" "This command creates the printable document. Depending on\n" " the projects setting you are required to specifiy a source for " "questionnaire\n" " IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:33 msgid "" "If using questionnaire IDs, create N questionnaires with randomized IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:36 msgid "" "If using questionnaire IDs, create questionnaires from the IDs read from the " "specified file." msgstr "" #: ../sdaps/cmdline/stamp.py:39 msgid "If using questionnaire IDs, create questionnaires for all stored IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:42 #, python-format msgid "Filename to store the data to (default: stamp_%%i.pdf)" msgstr "" #: ../sdaps/convert/__init__.py:37 #, python-format msgid "Could not apply 3D-transformation to image '%s', page %i!" msgstr "" #: ../sdaps/cover/__init__.py:40 msgid "SDAPS questionnaire" msgstr "" #: ../sdaps/csvdata/buddies.py:78 #, python-format msgid "Not importing unknown questionnaire ID \"%s\"" msgstr "" #: ../sdaps/gui/__init__.py:60 msgid "" "The survey does not have any images! Please add images (and run recognize) " "before using the GUI." msgstr "" #: ../sdaps/gui/__init__.py:212 msgid "Page|Invalid" msgstr "" #: ../sdaps/gui/__init__.py:215 #, python-format msgid "Page %i" msgid_plural "Page %i" msgstr[0] "" msgstr[1] "" #: ../sdaps/gui/__init__.py:257 msgid "Copyright © 2007-2014 The SDAPS Authors" msgstr "" #: ../sdaps/gui/__init__.py:259 msgid "Scripts for data acquisition with paper based surveys" msgstr "" #: ../sdaps/gui/__init__.py:260 msgid "http://sdaps.org" msgstr "" #: ../sdaps/gui/__init__.py:261 msgid "translator-credits" msgstr "" #: ../sdaps/gui/__init__.py:306 #, python-format msgid " of %i" msgstr "" #: ../sdaps/gui/__init__.py:307 #, python-format msgid "Recognition Quality: %.2f" msgstr "" #: ../sdaps/gui/__init__.py:323 msgid "" "You have reached the first page of the survey. Would you like to go to the " "last page?" msgstr "" #: ../sdaps/gui/__init__.py:325 msgid "Go to last page" msgstr "" #: ../sdaps/gui/__init__.py:347 msgid "" "You have reached the last page of the survey. Would you like to go to the " "first page?" msgstr "" #: ../sdaps/gui/__init__.py:349 msgid "Go to first page" msgstr "" #: ../sdaps/gui/__init__.py:465 msgid "Close without saving" msgstr "" #: ../sdaps/gui/__init__.py:469 msgid "" "Save the project before closing?\n" "\n" "If you do not save you may lose data." msgstr "" #: ../sdaps/gui/main_window.ui.h:1 msgid "Forward" msgstr "" #: ../sdaps/gui/main_window.ui.h:2 msgid "Previous" msgstr "" #: ../sdaps/gui/main_window.ui.h:3 msgid "Zoom In" msgstr "" #: ../sdaps/gui/main_window.ui.h:4 msgid "Zoom Out" msgstr "" #: ../sdaps/gui/main_window.ui.h:5 msgid "SDAPS" msgstr "" #: ../sdaps/gui/main_window.ui.h:6 msgid "_File" msgstr "" #: ../sdaps/gui/main_window.ui.h:7 msgid "_View" msgstr "" #: ../sdaps/gui/main_window.ui.h:8 msgid "_Help" msgstr "" #: ../sdaps/gui/main_window.ui.h:9 msgid "Recognize Page" msgstr "" #: ../sdaps/gui/main_window.ui.h:10 msgid "Page Rotated" msgstr "" #: ../sdaps/gui/main_window.ui.h:11 msgid "Sort by Quality" msgstr "" #: ../sdaps/gui/main_window.ui.h:12 msgid "label" msgstr "" #: ../sdaps/gui/widget_buddies.py:56 msgid "Global Properties" msgstr "" #: ../sdaps/gui/widget_buddies.py:60 msgid "Sheet valid" msgstr "" #: ../sdaps/gui/widget_buddies.py:61 msgid "Sheet Verified" msgstr "" #: ../sdaps/gui/widget_buddies.py:62 msgid "Page Verified" msgstr "" #: ../sdaps/gui/widget_buddies.py:63 ../sdaps/gui/widget_buddies.py:73 msgid "Empty" msgstr "" #: ../sdaps/gui/widget_buddies.py:84 ../sdaps/gui/widget_buddies.py:115 msgid "Questionnaire ID: " msgstr "" #: ../sdaps/image/__init__.py:48 msgid "" "It appears you have not build the C extension. Please run \"./setup.py build" "\" in the toplevel directory." msgstr "" #: ../sdaps/utils/latex.py:29 msgid "" "The latex character map is missing! Please build it using the supplied tool " "(create-latexmap.py)." msgstr "" #: ../sdaps/utils/latex.py:69 msgid "" "Generated string for LaTeX contains unicode characters. This may not work " "correctly and could mean the LaTeX character map needs to be updated." msgstr "" #: ../sdaps/utils/opencv.py:35 msgid "Cannot convert PDF files as poppler is not installed or usable!" msgstr "" #: ../sdaps/utils/opencv.py:44 msgid "File does not exist" msgstr "" #. The old code used to first filter, and then run; but that is #. a bit ineffective in a way #: ../sdaps/model/survey.py:411 #, python-format msgid "%i sheet" msgid_plural "%i sheets" msgstr[0] "" msgstr[1] "" #: ../sdaps/model/survey.py:427 #, python-format msgid "Processed %i of %i sheets, took %f seconds" msgstr "" #: ../sdaps/model/survey.py:474 msgid "" "A questionnaire that is printed in duplex needs an even amount of pages!" msgstr "" #: ../sdaps/model/survey.py:478 msgid "" "The 'classic' style only supports a maximum of six pages! Use the 'code128' " "style if you require more pages." msgstr "" #: ../sdaps/model/survey.py:491 msgid "IDs need to be integers in \"classic\" style!" msgstr "" #: ../sdaps/model/survey.py:497 #, python-format msgid "Invalid character %s in questionnaire ID \"%s\" in \"code128\" style!" msgstr "" #: ../sdaps/model/survey.py:501 msgid "" "SDAPS cannot draw a questionnaire ID with the \"custom\" style. Do this " "yourself somehow!" msgstr "" #. in simplex mode every page will have a matrix; it might be a None #. matrix though #: ../sdaps/recognize/buddies.py:76 #, python-format msgid "%s, %i: Matrix not recognized." msgstr "" #: ../sdaps/recognize/buddies.py:85 #, python-format msgid "%s, %i: Rotation not found." msgstr "" #. Copy the rotation over (if required) and print warning if the rotation is unknown #: ../sdaps/recognize/buddies.py:89 #, python-format msgid "Neither %s, %i or %s, %i has a known rotation!" msgstr "" #: ../sdaps/recognize/buddies.py:101 #, python-format msgid "%s, %i: Matrix not recognized (again)." msgstr "" #: ../sdaps/recognize/buddies.py:115 #, python-format msgid "%s, %i: Could not get page number." msgstr "" #. Whoa, that should not happen. #: ../sdaps/recognize/buddies.py:135 #, python-format msgid "Neither %s, %i or %s, %i has a known page number!" msgstr "" #. We don't touch the ignore flag in this case #. Simply print a message as this should *never* happen #: ../sdaps/recognize/buddies.py:146 #, python-format msgid "" "Got a simplex document where two adjacent pages had a known page number. " "This should never happen as even simplex scans are converted to duplex by " "inserting dummy pages. Maybe you did a simplex scan but added it in duplex " "mode? The pages in question are %s, %i and %s, %i." msgstr "" #: ../sdaps/recognize/buddies.py:163 #, python-format msgid "Images %s, %i and %s, %i do not have consecutive page numbers!" msgstr "" #: ../sdaps/recognize/buddies.py:179 #, python-format msgid "No page number for page %s, %i exists." msgstr "" #: ../sdaps/recognize/buddies.py:184 #, python-format msgid "Page number for page %s, %i already used by another image." msgstr "" #: ../sdaps/recognize/buddies.py:190 #, python-format msgid "Page number %i for page %s, %i is out of range." msgstr "" #: ../sdaps/recognize/buddies.py:207 #, python-format msgid "%s, %i: Could not read survey ID, but should be able to." msgstr "" #: ../sdaps/recognize/buddies.py:211 #, python-format msgid "Could not read survey ID of either %s, %i or %s, %i!" msgstr "" #. Broken survey ID ... #: ../sdaps/recognize/buddies.py:218 #, python-format msgid "Got a wrong survey ID (%s, %i)! It is %s, but should be %i." msgstr "" #: ../sdaps/recognize/buddies.py:240 #, python-format msgid "%s, %i: Could not read questionnaire ID, but should be able to." msgstr "" #: ../sdaps/recognize/buddies.py:246 #, python-format msgid "Could not read questionnaire ID of either %s, %i or %s, %i!" msgstr "" #: ../sdaps/recognize/buddies.py:276 msgid "" "Got different IDs on different pages for at least one sheet! Do *NOT* try to " "use filters with this survey! You have to run a \"reorder\" step for this to " "work properly!" msgstr "" #: ../sdaps/recognize/buddies.py:337 msgid "No style buddy loaded. This needs to be done for the \"custom\" style!" msgstr "" #: ../sdaps/report/answers.py:188 #, python-format msgid "Answers: %i" msgstr "" #: ../sdaps/report/answers.py:190 #, python-format msgid "Mean: %.2f" msgstr "" #: ../sdaps/report/answers.py:192 #, python-format msgid "Standard Deviation: %.2f" msgstr "" #: ../sdaps/report/__init__.py:75 ../sdaps/reporttex/__init__.py:140 msgid "Turned in Questionnaires" msgstr "" #: ../sdaps/report/__init__.py:92 ../sdaps/reporttex/__init__.py:139 msgid "sdaps report" msgstr "" #: ../sdaps/reset/__init__.py:29 msgid "Removing stored data..." msgstr "" #: ../sdaps/setup/buddies.py:62 #, python-format msgid "Head %(l0)i got no title." msgstr "" #: ../sdaps/setup/buddies.py:74 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no question." msgstr "" #: ../sdaps/setup/buddies.py:114 #, python-format msgid "Error in question \"%s\"" msgstr "" #: ../sdaps/setup/buddies.py:118 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no boxes." msgstr "" #: ../sdaps/setup/buddies.py:167 #, python-format msgid "%(class)s %(l0)i.%(l1)i lower box out of range." msgstr "" #: ../sdaps/setup/buddies.py:172 #, python-format msgid "%(class)s %(l0)i.%(l1)i upper box out of range." msgstr "" #: ../sdaps/setup/buddies.py:177 #, python-format msgid "%(class)s %(l0)i.%(l1)i lower box not before upper box." msgstr "" #: ../sdaps/setup/buddies.py:213 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly two answers." msgstr "" #: ../sdaps/setup/buddies.py:234 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly one box." msgstr "" #: ../sdaps/stamp/__init__.py:38 msgid "" "You may not specify the number of sheets for this survey. All questionnaires " "will be identical as the survey has been configured to not use questionnaire " "IDs for each sheet." msgstr "" #: ../sdaps/stamp/__init__.py:76 msgid "" "This survey has been configured to use questionnaire IDs. Each questionnaire " "will be unique. You need to use on of the options to add new IDs or use the " "existing ones." msgstr "" #: ../sdaps/stamp/latex.py:18 msgid "" "There should be no need to stamp a SDAPS Project that uses LaTeX and does " "not have different questionnaire IDs printed on each sheet.\n" "I am going to do so anyways." msgstr "" #: ../sdaps/stamp/latex.py:26 #, python-format msgid "Running %s now multiple times to generate the stamped questionnaire." msgstr "" #: ../sdaps/stamp/latex.py:30 ../sdaps/setuptex/__init__.py:108 #: ../sdaps/setuptex/__init__.py:149 ../sdaps/reporttex/__init__.py:162 #, python-format msgid "Error running \"%s\" to compile the LaTeX file." msgstr "" #: ../sdaps/stamp/latex.py:36 #, python-format msgid "" "An error occured during creation of the report. Temporary files left in '%s'." msgstr "" #: ../sdaps/setuptex/__init__.py:46 msgid "The survey directory already exists." msgstr "" #: ../sdaps/setuptex/__init__.py:51 #, python-format msgid "Unknown file type (%s). questionnaire_tex should be of type text/x-tex." msgstr "" #: ../sdaps/setuptex/__init__.py:52 msgid "Will keep going, but expect failure!" msgstr "" #: ../sdaps/setuptex/__init__.py:57 #, python-format msgid "Unknown file type (%s). additionalqobjects should be text/plain." msgstr "" #: ../sdaps/setuptex/__init__.py:104 #, python-format msgid "Running %s now multiple times to generate the questionnaire." msgstr "" #: ../sdaps/setuptex/__init__.py:123 msgid "Caught an Exception while parsing the SDAPS file. The current state is:" msgstr "" #: ../sdaps/setuptex/__init__.py:137 msgid "" "Some combination of options and project properties do not work. Aborted " "Setup." msgstr "" #: ../sdaps/setuptex/__init__.py:144 #, python-format msgid "Running %s now multiple imes to generate the questionnaire." msgstr "" #: ../sdaps/setuptex/__init__.py:163 msgid "" "An error occured in the setup routine. The survey directory still exists. " "You can for example check the questionnaire.log file for LaTeX compile " "errors." msgstr "" #: ../sdaps/reporttex/__init__.py:107 msgid "author|Unknown" msgstr "" #: ../sdaps/reporttex/__init__.py:138 msgid "tex language|english" msgstr "" #: ../sdaps/reporttex/__init__.py:155 #, python-format msgid "The TeX project with the report data is located at '%s'." msgstr "" #: ../sdaps/reporttex/__init__.py:158 #, python-format msgid "Running %s now multiple times to generate the report." msgstr "" #: ../sdaps/reporttex/__init__.py:168 #, python-format msgid "An occured during creation of the report. Temporary files left in '%s'." msgstr "" sdaps-1.9.8/po/si.po0000644000175000000660000006116713410742232015001 0ustar benjaminlock00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:10+0100\n" "PO-Revision-Date: 2018-10-09 03:36+0000\n" "Last-Translator: Menuka Ishan \n" "Language-Team: Sinhala \n" "Language: si\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 3.2.1\n" #: ../sdaps/script.py:41 msgid "SDAPS -- Paper based survey tool." msgstr "SDAPS - මුද්‍රිත මාධ්‍ය පදනම් සමීක්ෂණ මෙවලම" #: ../sdaps/script.py:45 msgid "command list|Commands:" msgstr "" #: ../sdaps/script.py:50 msgid "project directory|The SDAPS project." msgstr "" #: ../sdaps/add/__init__.py:55 #, python-format msgid "" "Invalid input file %s. You need to specify a (multipage) monochrome TIFF as " "input." msgstr "" #: ../sdaps/add/__init__.py:67 #, python-format msgid "" "Not adding %s because it has a wrong page count (needs to be a mulitple of " "%i)." msgstr "" #: ../sdaps/boxgallery/__init__.py:108 #, python-format msgid "Rendering boxgallery for metric \"%s\"." msgstr "" #: ../sdaps/log.py:37 msgid "Warning: " msgstr "අවවාදයයි: " #: ../sdaps/log.py:41 msgid "Error: " msgstr "දෝෂයක්: " #: ../sdaps/cmdline/add.py:31 msgid "Add scanned questionnaires to the survey." msgstr "" #: ../sdaps/cmdline/add.py:32 msgid "" "This command is used to add scanned images to the survey.\n" " The image data needs to be a (multipage) 300dpi monochrome TIFF file. " "You\n" " may choose not to copy the data into the project directory. In that " "case\n" " the data will be referenced using a relative path." msgstr "" #: ../sdaps/cmdline/add.py:38 msgid "Convert given files and add the result." msgstr "" #: ../sdaps/cmdline/add.py:43 msgid "" "Do a 3D-transformation after finding the corner marks. If the\n" " corner marks are not found then the image will be added as-is." msgstr "" #: ../sdaps/cmdline/add.py:49 msgid "" "Force adding the images even if the page count is wrong (only use if you " "know what you are doing)." msgstr "" #: ../sdaps/cmdline/add.py:53 msgid "Copy the files into the directory (default)." msgstr "" #: ../sdaps/cmdline/add.py:58 msgid "Do not copy the files into the directory." msgstr "" #: ../sdaps/cmdline/add.py:62 msgid "" "Images contain a duplex scan of a simplex questionnaire (default: simplex " "scan)." msgstr "" #: ../sdaps/cmdline/add.py:68 ../sdaps/cmdline/convert.py:48 msgid "A number of TIFF image files." msgstr "" #: ../sdaps/cmdline/add.py:94 msgid "The --no-copy option is not compatible with --convert!" msgstr "" #: ../sdaps/cmdline/add.py:103 msgid "Converting input files into a single temporary file." msgstr "" #: ../sdaps/cmdline/add.py:115 msgid "" "The page count of the created temporary file does not work with this survey." msgstr "" #: ../sdaps/cmdline/add.py:120 msgid "Running the conversion failed." msgstr "" #: ../sdaps/cmdline/add.py:126 #, python-format msgid "Processing %s" msgstr "" #: ../sdaps/cmdline/add.py:130 ../sdaps/reset/__init__.py:33 msgid "Done" msgstr "" #: ../sdaps/cmdline/annotate.py:28 msgid "Annotate the questionnaire and show the recognized positions." msgstr "" #: ../sdaps/cmdline/annotate.py:29 msgid "" "This command is mainly a debug utility. It creates an\n" " annotated version of the questionnaire, with the information that SDAPS\n" " knows about it overlayed on top." msgstr "" #: ../sdaps/cmdline/boxgallery.py:31 msgid "Create PDFs with boxes sorted by the detection heuristics." msgstr "" #: ../sdaps/cmdline/boxgallery.py:32 msgid "" "SDAPS uses multiple heuristics to detect determine the\n" " state of checkboxes. There is a list for each heuristic giving the " "expected\n" " state and the quality of the value (see defs.py). Using this command a " "PDF\n" " will be created for each of the heuristics so that one can adjust the\n" " values." msgstr "" #: ../sdaps/cmdline/boxgallery.py:40 msgid "" "Reruns part of the recognition process and retrieves debug images from this " "step." msgstr "" #: ../sdaps/cmdline/convert.py:30 msgid "Convert a set of images to the correct image format." msgstr "" #: ../sdaps/cmdline/convert.py:31 msgid "" "This command can be used if you scanned files in something\n" " other than the expected monochrome TIFF mode. All given files will\n" " be loaded, converted to monochrome and stored in a multipage 1bpp\n" " TIFF file. Optionally, you can select \"3D transformation\"\\ ,which " "may facilitate\n" " working with photos of questionnaires instead of scans." msgstr "" #: ../sdaps/cmdline/convert.py:38 msgid "" "Do a 3D-transformation after finding the corner marks.\n" " If they are not found, the image will be processed as-is." msgstr "" #: ../sdaps/cmdline/convert.py:44 msgid "The location of the output file." msgstr "" #: ../sdaps/cmdline/convert.py:57 msgid "No output filename specified!" msgstr "" #: ../sdaps/cmdline/cover.py:27 msgid "Create a cover for the questionnaires." msgstr "" #: ../sdaps/cmdline/cover.py:28 msgid "" "This command creates a cover page for questionnaires. All\n" " the metadata of the survey will be printed on the page." msgstr "" #: ../sdaps/cmdline/cover.py:31 #, python-format msgid "Filename to store the data to (default: cover_%%i.pdf)" msgstr "" #: ../sdaps/cmdline/csvdata.py:34 msgid "Import or export data to/from CSV files." msgstr "" #: ../sdaps/cmdline/csvdata.py:35 msgid "" "Import or export data to/from a CSV file. The first line\n" " is a header which defines questionnaire_id and global_id, and a column\n" " for each checkbox and textfield. Note that the import is currently very\n" " limited, as you need to specifiy the questionnaire ID to select the " "sheet\n" " which should be updated." msgstr "" #: ../sdaps/cmdline/csvdata.py:44 msgid "Export data to CSV file." msgstr "" #: ../sdaps/cmdline/csvdata.py:46 #, python-format msgid "Filename to store the data to (default: data_%%i.csv)" msgstr "" #: ../sdaps/cmdline/csvdata.py:48 msgid "The delimiter used in the CSV file (default ',')" msgstr "" #: ../sdaps/cmdline/csvdata.py:52 ../sdaps/cmdline/report.py:31 #: ../sdaps/cmdline/reporttex.py:52 msgid "Filter to only export a partial dataset." msgstr "" #: ../sdaps/cmdline/csvdata.py:54 msgid "Export images of freeform fields." msgstr "" #: ../sdaps/cmdline/csvdata.py:60 msgid "Export an image for each question that includes all boxes." msgstr "" #: ../sdaps/cmdline/csvdata.py:66 msgid "Export the recognition quality for each checkbox." msgstr "" #: ../sdaps/cmdline/csvdata.py:74 msgid "Import data to from a CSV file." msgstr "" #: ../sdaps/cmdline/csvdata.py:76 msgid "The file to import." msgstr "" #: ../sdaps/cmdline/gui.py:28 msgid "Launch a GUI. You can view and alter the (recognized) answers with it." msgstr "" #: ../sdaps/cmdline/gui.py:29 msgid "" "This command launches a graphical user interface that can\n" " be used to correct answers. You need to run \"recognize\" before using " "it.\n" " " msgstr "" #: ../sdaps/cmdline/gui.py:34 msgid "Filter to only show a partial dataset." msgstr "" #: ../sdaps/cmdline/ids.py:29 msgid "Export and import questionnaire IDs." msgstr "" #: ../sdaps/cmdline/ids.py:30 msgid "" "This command can be used to import and export questionnaire\n" " IDs. It only makes sense in projects where such an ID is printed on the\n" " questionnaire. Note that you can also add IDs by using the stamp " "command,\n" " which will give you the PDF at the same time." msgstr "" #: ../sdaps/cmdline/ids.py:35 #, python-format msgid "Filename to store the data to (default: ids_%%i)" msgstr "" #: ../sdaps/cmdline/ids.py:38 msgid "Add IDs to the internal list from the specified file." msgstr "" #: ../sdaps/cmdline/info.py:28 msgid "Display and modify metadata of project." msgstr "" #: ../sdaps/cmdline/info.py:29 msgid "" "This command lets you modify the metadata of the SDAPS\n" " project. You can modify, add and remove arbitrary keys that will be " "printed\n" " on the report. The only key that always exist is \"title\".\n" " If no key is given then a list of defined keys is printed." msgstr "" #: ../sdaps/cmdline/info.py:36 msgid "Delete the key and value pair." msgstr "" #: ../sdaps/cmdline/info.py:40 msgid "The key to display or modify." msgstr "" #: ../sdaps/cmdline/info.py:44 msgid "Set the given key to this value." msgstr "" #: ../sdaps/cmdline/info.py:69 msgid "Existing fields:\n" msgstr "" #: ../sdaps/cmdline/recognize.py:28 msgid "Run the optical mark recognition." msgstr "" #: ../sdaps/cmdline/recognize.py:29 msgid "" "Iterates over all images and runs the optical mark\n" " recognition. It will reevaluate sheets even if \"recognize\" has " "already\n" " run or manual changes were made." msgstr "" #: ../sdaps/cmdline/recognize.py:34 msgid "" "Only identify the page properties, but don't recognize the checkbox states." msgstr "" #: ../sdaps/cmdline/recognize.py:39 msgid "" "Rerun the recognition for all pages. The default is to skip all pages that " "were recognized or verified already." msgstr "" #: ../sdaps/cmdline/reorder.py:26 msgid "Reorder pages according to questionnaire ID." msgstr "" #: ../sdaps/cmdline/reorder.py:27 msgid "" "This command reorders all pages according to the already\n" " recognized questionnaire ID. To use it add all the files to the " "project,\n" " then run a partial recognition using \"recognize --identify\". After " "this\n" " you have to run this command to reorder the data for the real " "recognition.\n" " " msgstr "" #: ../sdaps/cmdline/report.py:26 msgid "Create a PDF report." msgstr "" #: ../sdaps/cmdline/report.py:27 msgid "" "This command creates a PDF report using reportlab that\n" " contains statistics and if selected the freeform fields." msgstr "" #: ../sdaps/cmdline/report.py:33 msgid "Create a filtered report for every checkbox." msgstr "" #: ../sdaps/cmdline/report.py:36 msgid "Short format (without freeform text fields)." msgstr "" #: ../sdaps/cmdline/report.py:41 msgid "Detailed output. (default)" msgstr "" #: ../sdaps/cmdline/report.py:47 ../sdaps/cmdline/reporttex.py:30 msgid "" "Do not include original images in the report. This is useful if there are " "privacy concerns." msgstr "" #: ../sdaps/cmdline/report.py:52 ../sdaps/cmdline/reporttex.py:35 msgid "Do not use substitutions instead of images." msgstr "" #: ../sdaps/cmdline/report.py:58 ../sdaps/cmdline/reporttex.py:46 msgid "The paper size used for the output (default: locale dependent)" msgstr "" #: ../sdaps/cmdline/report.py:61 ../sdaps/cmdline/reporttex.py:49 #, python-format msgid "Filename to store the data to (default: report_%%i.pdf)" msgstr "" #: ../sdaps/cmdline/reporttex.py:26 msgid "Create a PDF report using LaTeX." msgstr "" #: ../sdaps/cmdline/reporttex.py:27 msgid "" "This command creates a PDF report using LaTeX that\n" " contains statistics and freeform fields." msgstr "" #: ../sdaps/cmdline/reporttex.py:41 msgid "Save the generated TeX files instead of the final PDF." msgstr "" #: ../sdaps/cmdline/reset.py:26 msgid "Reset project into original state" msgstr "" #: ../sdaps/cmdline/reset.py:27 msgid "" "This command does a full reset of the project. All data\n" " will be discarded and only the empty project is left.\n" " " msgstr "" #: ../sdaps/cmdline/setup.py:27 msgid "Create a new survey using a LaTeX document." msgstr "" #: ../sdaps/cmdline/setup.py:28 msgid "" "Create a new survey from a LaTeX document. You need to\n" " be using the SDAPS class. All the metadata and options for the project\n" " can be set inside the LaTeX document." msgstr "" #: ../sdaps/cmdline/setup.py:33 msgid "The LaTeX Document" msgstr "" #: ../sdaps/cmdline/setup.py:35 msgid "" "Additional files that are required by the LaTeX document and need to be " "copied into the project directory." msgstr "" #: ../sdaps/cmdline/setup.py:39 msgid "Additional questions that are not part of the questionnaire." msgstr "" #: ../sdaps/cmdline/stamp.py:26 msgid "Add marks for automatic processing." msgstr "" #: ../sdaps/cmdline/stamp.py:27 msgid "" "This command creates the printable document. Depending on\n" " the projects setting you are required to specifiy a source for " "questionnaire\n" " IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:33 msgid "" "If using questionnaire IDs, create N questionnaires with randomized IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:36 msgid "" "If using questionnaire IDs, create questionnaires from the IDs read from the " "specified file." msgstr "" #: ../sdaps/cmdline/stamp.py:39 msgid "If using questionnaire IDs, create questionnaires for all stored IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:42 #, python-format msgid "Filename to store the data to (default: stamp_%%i.pdf)" msgstr "" #: ../sdaps/convert/__init__.py:37 #, python-format msgid "Could not apply 3D-transformation to image '%s', page %i!" msgstr "" #: ../sdaps/cover/__init__.py:40 msgid "SDAPS questionnaire" msgstr "" #: ../sdaps/csvdata/buddies.py:77 #, python-format msgid "Not importing unknown questionnaire ID \"%s\"" msgstr "" #: ../sdaps/gui/__init__.py:59 msgid "" "The survey does not have any images! Please add images (and run recognize) " "before using the GUI." msgstr "" #: ../sdaps/gui/__init__.py:211 msgid "Page|Invalid" msgstr "" #: ../sdaps/gui/__init__.py:214 #, python-format msgid "Page %i" msgid_plural "Page %i" msgstr[0] "" msgstr[1] "" #: ../sdaps/gui/__init__.py:256 msgid "Copyright © 2007-2014 The SDAPS Authors" msgstr "" #: ../sdaps/gui/__init__.py:258 msgid "Scripts for data acquisition with paper based surveys" msgstr "" #: ../sdaps/gui/__init__.py:259 msgid "http://sdaps.org" msgstr "" #: ../sdaps/gui/__init__.py:260 msgid "translator-credits" msgstr "" #: ../sdaps/gui/__init__.py:305 #, python-format msgid " of %i" msgstr "" #: ../sdaps/gui/__init__.py:306 #, python-format msgid "Recognition Quality: %.2f" msgstr "" #: ../sdaps/gui/__init__.py:322 msgid "" "You have reached the first page of the survey. Would you like to go to the " "last page?" msgstr "" #: ../sdaps/gui/__init__.py:324 msgid "Go to last page" msgstr "" #: ../sdaps/gui/__init__.py:346 msgid "" "You have reached the last page of the survey. Would you like to go to the " "first page?" msgstr "" #: ../sdaps/gui/__init__.py:348 msgid "Go to first page" msgstr "" #: ../sdaps/gui/__init__.py:457 msgid "Close without saving" msgstr "" #: ../sdaps/gui/__init__.py:461 msgid "" "Save the project before closing?\n" "\n" "If you do not save you may loose data." msgstr "" #: ../sdaps/gui/main_window.ui.h:1 msgid "Forward" msgstr "" #: ../sdaps/gui/main_window.ui.h:2 msgid "Previous" msgstr "" #: ../sdaps/gui/main_window.ui.h:3 msgid "Zoom In" msgstr "" #: ../sdaps/gui/main_window.ui.h:4 msgid "Zoom Out" msgstr "" #: ../sdaps/gui/main_window.ui.h:5 msgid "SDAPS" msgstr "" #: ../sdaps/gui/main_window.ui.h:6 msgid "_File" msgstr "" #: ../sdaps/gui/main_window.ui.h:7 msgid "_View" msgstr "" #: ../sdaps/gui/main_window.ui.h:8 msgid "_Help" msgstr "" #: ../sdaps/gui/main_window.ui.h:9 msgid "Page Rotated" msgstr "" #: ../sdaps/gui/main_window.ui.h:10 msgid "Sort by Quality" msgstr "" #: ../sdaps/gui/main_window.ui.h:11 msgid "label" msgstr "" #: ../sdaps/gui/widget_buddies.py:56 msgid "Global Properties" msgstr "" #: ../sdaps/gui/widget_buddies.py:60 msgid "Sheet valid" msgstr "" #: ../sdaps/gui/widget_buddies.py:61 msgid "Sheet Verified" msgstr "" #: ../sdaps/gui/widget_buddies.py:62 msgid "Page Verified" msgstr "" #: ../sdaps/gui/widget_buddies.py:63 msgid "Empty" msgstr "" #: ../sdaps/gui/widget_buddies.py:75 ../sdaps/gui/widget_buddies.py:105 msgid "Questionnaire ID: " msgstr "" #: ../sdaps/image/__init__.py:47 msgid "" "It appears you have not build the C extension. Please run \"./setup.py build" "\" in the toplevel directory." msgstr "" #: ../sdaps/utils/latex.py:29 msgid "" "The latex character map is missing! Please build it using the supplied tool " "(create-latexmap.py)." msgstr "" #: ../sdaps/utils/latex.py:69 msgid "" "Generated string for LaTeX contains unicode characters. This may not work " "correctly and could mean the LaTeX character map needs to be updated." msgstr "" #: ../sdaps/utils/opencv.py:35 msgid "Cannot convert PDF files as poppler is not installed or usable!" msgstr "" #: ../sdaps/utils/opencv.py:44 msgid "File does not exist" msgstr "" #. The old code used to first filter, and then run; but that is #. a bit ineffective in a way #: ../sdaps/model/survey.py:386 #, python-format msgid "%i sheet" msgid_plural "%i sheets" msgstr[0] "" msgstr[1] "" #: ../sdaps/model/survey.py:402 #, python-format msgid "Processed %i of %i sheets, took %f seconds" msgstr "" #: ../sdaps/model/survey.py:449 msgid "" "A questionnaire that is printed in duplex needs an even amount of pages!" msgstr "" #: ../sdaps/model/survey.py:453 msgid "" "The 'classic' style only supports a maximum of six pages! Use the 'code128' " "style if you require more pages." msgstr "" #: ../sdaps/model/survey.py:466 msgid "IDs need to be integers in \"classic\" style!" msgstr "" #: ../sdaps/model/survey.py:472 #, python-format msgid "Invalid character %s in questionnaire ID \"%s\" in \"code128\" style!" msgstr "" #: ../sdaps/model/survey.py:476 msgid "" "SDAPS cannot draw a questionnaire ID with the \"custom\" style. Do this " "yourself somehow!" msgstr "" #. in simplex mode every page will have a matrix; it might be a None #. matrix though #: ../sdaps/recognize/buddies.py:71 #, python-format msgid "%s, %i: Matrix not recognized." msgstr "" #: ../sdaps/recognize/buddies.py:80 #, python-format msgid "%s, %i: Rotation not found." msgstr "" #. Copy the rotation over (if required) and print warning if the rotation is unknown #: ../sdaps/recognize/buddies.py:84 #, python-format msgid "Neither %s, %i or %s, %i has a known rotation!" msgstr "" #: ../sdaps/recognize/buddies.py:96 #, python-format msgid "%s, %i: Matrix not recognized (again)." msgstr "" #: ../sdaps/recognize/buddies.py:110 #, python-format msgid "%s, %i: Could not get page number." msgstr "" #. Whoa, that should not happen. #: ../sdaps/recognize/buddies.py:130 #, python-format msgid "Neither %s, %i or %s, %i has a known page number!" msgstr "" #. We don't touch the ignore flag in this case #. Simply print a message as this should *never* happen #: ../sdaps/recognize/buddies.py:141 #, python-format msgid "" "Got a simplex document where two adjacent pages had a known page number. " "This should never happen as even simplex scans are converted to duplex by " "inserting dummy pages. Maybe you did a simplex scan but added it in duplex " "mode? The pages in question are %s, %i and %s, %i." msgstr "" #: ../sdaps/recognize/buddies.py:158 #, python-format msgid "Images %s, %i and %s, %i do not have consecutive page numbers!" msgstr "" #: ../sdaps/recognize/buddies.py:174 #, python-format msgid "No page number for page %s, %i exists." msgstr "" #: ../sdaps/recognize/buddies.py:179 #, python-format msgid "Page number for page %s, %i already used by another image." msgstr "" #: ../sdaps/recognize/buddies.py:185 #, python-format msgid "Page number %i for page %s, %i is out of range." msgstr "" #: ../sdaps/recognize/buddies.py:202 #, python-format msgid "%s, %i: Could not read survey ID, but should be able to." msgstr "" #: ../sdaps/recognize/buddies.py:206 #, python-format msgid "Could not read survey ID of either %s, %i or %s, %i!" msgstr "" #. Broken survey ID ... #: ../sdaps/recognize/buddies.py:213 #, python-format msgid "Got a wrong survey ID (%s, %i)! It is %s, but should be %i." msgstr "" #: ../sdaps/recognize/buddies.py:235 #, python-format msgid "%s, %i: Could not read questionnaire ID, but should be able to." msgstr "" #: ../sdaps/recognize/buddies.py:241 #, python-format msgid "Could not read questionnaire ID of either %s, %i or %s, %i!" msgstr "" #: ../sdaps/recognize/buddies.py:271 msgid "" "Got different IDs on different pages for at least one sheet! Do *NOT* try to " "use filters with this survey! You have to run a \"reorder\" step for this to " "work properly!" msgstr "" #: ../sdaps/recognize/buddies.py:326 msgid "No style buddy loaded. This needs to be done for the \"custom\" style!" msgstr "" #: ../sdaps/report/answers.py:188 #, python-format msgid "Answers: %i" msgstr "" #: ../sdaps/report/answers.py:190 #, python-format msgid "Mean: %.2f" msgstr "" #: ../sdaps/report/answers.py:192 #, python-format msgid "Standard Deviation: %.2f" msgstr "" #: ../sdaps/report/__init__.py:75 ../sdaps/reporttex/__init__.py:140 msgid "Turned in Questionnaires" msgstr "" #: ../sdaps/report/__init__.py:92 ../sdaps/reporttex/__init__.py:139 msgid "sdaps report" msgstr "" #: ../sdaps/reset/__init__.py:29 msgid "Removing stored data..." msgstr "" #: ../sdaps/setup/buddies.py:62 #, python-format msgid "Head %(l0)i got no title." msgstr "" #: ../sdaps/setup/buddies.py:74 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no question." msgstr "" #: ../sdaps/setup/buddies.py:114 #, python-format msgid "Error in question \"%s\"" msgstr "" #: ../sdaps/setup/buddies.py:118 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no boxes." msgstr "" #: ../sdaps/setup/buddies.py:167 #, python-format msgid "%(class)s %(l0)i.%(l1)i lower box out of range." msgstr "" #: ../sdaps/setup/buddies.py:172 #, python-format msgid "%(class)s %(l0)i.%(l1)i upper box out of range." msgstr "" #: ../sdaps/setup/buddies.py:177 #, python-format msgid "%(class)s %(l0)i.%(l1)i lower box not before upper box." msgstr "" #: ../sdaps/setup/buddies.py:213 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly two answers." msgstr "" #: ../sdaps/setup/buddies.py:234 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly one box." msgstr "" #: ../sdaps/stamp/__init__.py:38 msgid "" "You may not specify the number of sheets for this survey. All questionnaires " "will be identical as the survey has been configured to not use questionnaire " "IDs for each sheet." msgstr "" #: ../sdaps/stamp/__init__.py:76 msgid "" "This survey has been configured to use questionnaire IDs. Each questionnaire " "will be unique. You need to use on of the options to add new IDs or use the " "existing ones." msgstr "" #: ../sdaps/stamp/latex.py:18 msgid "" "There should be no need to stamp a SDAPS Project that uses LaTeX and does " "not have different questionnaire IDs printed on each sheet.\n" "I am going to do so anyways." msgstr "" #: ../sdaps/stamp/latex.py:26 #, python-format msgid "Running %s now twice to generate the stamped questionnaire." msgstr "" #: ../sdaps/stamp/latex.py:30 ../sdaps/setuptex/__init__.py:107 #: ../sdaps/setuptex/__init__.py:148 ../sdaps/reporttex/__init__.py:162 #, python-format msgid "Error running \"%s\" to compile the LaTeX file." msgstr "" #: ../sdaps/stamp/latex.py:36 #, python-format msgid "" "An error occured during creation of the report. Temporary files left in '%s'." msgstr "" #: ../sdaps/setuptex/__init__.py:46 msgid "The survey directory already exists." msgstr "" #: ../sdaps/setuptex/__init__.py:51 #, python-format msgid "Unknown file type (%s). questionnaire_tex should be of type text/x-tex." msgstr "" #: ../sdaps/setuptex/__init__.py:52 msgid "Will keep going, but expect failure!" msgstr "" #: ../sdaps/setuptex/__init__.py:57 #, python-format msgid "Unknown file type (%s). additionalqobjects should be text/plain." msgstr "" #: ../sdaps/setuptex/__init__.py:103 ../sdaps/setuptex/__init__.py:143 #, python-format msgid "Running %s now twice to generate the questionnaire." msgstr "" #: ../sdaps/setuptex/__init__.py:122 msgid "Caught an Exception while parsing the SDAPS file. The current state is:" msgstr "" #: ../sdaps/setuptex/__init__.py:136 msgid "" "Some combination of options and project properties do not work. Aborted " "Setup." msgstr "" #: ../sdaps/setuptex/__init__.py:162 msgid "" "An error occured in the setup routine. The survey directory still exists. " "You can for example check the questionnaire.log file for LaTeX compile " "errors." msgstr "" #: ../sdaps/reporttex/__init__.py:107 msgid "author|Unknown" msgstr "" #: ../sdaps/reporttex/__init__.py:138 msgid "tex language|english" msgstr "" #: ../sdaps/reporttex/__init__.py:155 #, python-format msgid "The TeX project with the report data is located at '%s'." msgstr "" #: ../sdaps/reporttex/__init__.py:158 #, python-format msgid "Running %s now twice to generate the report." msgstr "" #: ../sdaps/reporttex/__init__.py:168 #, python-format msgid "An occured during creation of the report. Temporary files left in '%s'." msgstr "" sdaps-1.9.8/po/sv.po0000644000175000000660000006062313410742232015012 0ustar benjaminlock00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:10+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: sv\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../sdaps/script.py:41 msgid "SDAPS -- Paper based survey tool." msgstr "" #: ../sdaps/script.py:45 msgid "command list|Commands:" msgstr "" #: ../sdaps/script.py:50 msgid "project directory|The SDAPS project." msgstr "" #: ../sdaps/add/__init__.py:55 #, python-format msgid "" "Invalid input file %s. You need to specify a (multipage) monochrome TIFF as " "input." msgstr "" #: ../sdaps/add/__init__.py:67 #, python-format msgid "" "Not adding %s because it has a wrong page count (needs to be a mulitple of " "%i)." msgstr "" #: ../sdaps/boxgallery/__init__.py:108 #, python-format msgid "Rendering boxgallery for metric \"%s\"." msgstr "" #: ../sdaps/log.py:37 msgid "Warning: " msgstr "" #: ../sdaps/log.py:41 msgid "Error: " msgstr "" #: ../sdaps/cmdline/add.py:31 msgid "Add scanned questionnaires to the survey." msgstr "" #: ../sdaps/cmdline/add.py:32 msgid "" "This command is used to add scanned images to the survey.\n" " The image data needs to be a (multipage) 300dpi monochrome TIFF file. " "You\n" " may choose not to copy the data into the project directory. In that " "case\n" " the data will be referenced using a relative path." msgstr "" #: ../sdaps/cmdline/add.py:38 msgid "Convert given files and add the result." msgstr "" #: ../sdaps/cmdline/add.py:43 msgid "" "Do a 3D-transformation after finding the corner marks. If the\n" " corner marks are not found then the image will be added as-is." msgstr "" #: ../sdaps/cmdline/add.py:49 msgid "" "Force adding the images even if the page count is wrong (only use if you " "know what you are doing)." msgstr "" #: ../sdaps/cmdline/add.py:53 msgid "Copy the files into the directory (default)." msgstr "" #: ../sdaps/cmdline/add.py:58 msgid "Do not copy the files into the directory." msgstr "" #: ../sdaps/cmdline/add.py:62 msgid "" "Images contain a duplex scan of a simplex questionnaire (default: simplex " "scan)." msgstr "" #: ../sdaps/cmdline/add.py:68 ../sdaps/cmdline/convert.py:48 msgid "A number of TIFF image files." msgstr "" #: ../sdaps/cmdline/add.py:94 msgid "The --no-copy option is not compatible with --convert!" msgstr "" #: ../sdaps/cmdline/add.py:103 msgid "Converting input files into a single temporary file." msgstr "" #: ../sdaps/cmdline/add.py:115 msgid "" "The page count of the created temporary file does not work with this survey." msgstr "" #: ../sdaps/cmdline/add.py:120 msgid "Running the conversion failed." msgstr "" #: ../sdaps/cmdline/add.py:126 #, python-format msgid "Processing %s" msgstr "" #: ../sdaps/cmdline/add.py:130 ../sdaps/reset/__init__.py:33 msgid "Done" msgstr "" #: ../sdaps/cmdline/annotate.py:28 msgid "Annotate the questionnaire and show the recognized positions." msgstr "" #: ../sdaps/cmdline/annotate.py:29 msgid "" "This command is mainly a debug utility. It creates an\n" " annotated version of the questionnaire, with the information that SDAPS\n" " knows about it overlayed on top." msgstr "" #: ../sdaps/cmdline/boxgallery.py:31 msgid "Create PDFs with boxes sorted by the detection heuristics." msgstr "" #: ../sdaps/cmdline/boxgallery.py:32 msgid "" "SDAPS uses multiple heuristics to detect determine the\n" " state of checkboxes. There is a list for each heuristic giving the " "expected\n" " state and the quality of the value (see defs.py). Using this command a " "PDF\n" " will be created for each of the heuristics so that one can adjust the\n" " values." msgstr "" #: ../sdaps/cmdline/boxgallery.py:40 msgid "" "Reruns part of the recognition process and retrieves debug images from this " "step." msgstr "" #: ../sdaps/cmdline/convert.py:30 msgid "Convert a set of images to the correct image format." msgstr "" #: ../sdaps/cmdline/convert.py:31 msgid "" "This command can be used if you scanned files in something\n" " other than the expected monochrome TIFF mode. All given files will\n" " be loaded, converted to monochrome and stored in a multipage 1bpp\n" " TIFF file. Optionally, you can select \"3D transformation\"\\ ,which " "may facilitate\n" " working with photos of questionnaires instead of scans." msgstr "" #: ../sdaps/cmdline/convert.py:38 msgid "" "Do a 3D-transformation after finding the corner marks.\n" " If they are not found, the image will be processed as-is." msgstr "" #: ../sdaps/cmdline/convert.py:44 msgid "The location of the output file." msgstr "" #: ../sdaps/cmdline/convert.py:57 msgid "No output filename specified!" msgstr "" #: ../sdaps/cmdline/cover.py:27 msgid "Create a cover for the questionnaires." msgstr "" #: ../sdaps/cmdline/cover.py:28 msgid "" "This command creates a cover page for questionnaires. All\n" " the metadata of the survey will be printed on the page." msgstr "" #: ../sdaps/cmdline/cover.py:31 #, python-format msgid "Filename to store the data to (default: cover_%%i.pdf)" msgstr "" #: ../sdaps/cmdline/csvdata.py:34 msgid "Import or export data to/from CSV files." msgstr "" #: ../sdaps/cmdline/csvdata.py:35 msgid "" "Import or export data to/from a CSV file. The first line\n" " is a header which defines questionnaire_id and global_id, and a column\n" " for each checkbox and textfield. Note that the import is currently very\n" " limited, as you need to specifiy the questionnaire ID to select the " "sheet\n" " which should be updated." msgstr "" #: ../sdaps/cmdline/csvdata.py:44 msgid "Export data to CSV file." msgstr "" #: ../sdaps/cmdline/csvdata.py:46 #, python-format msgid "Filename to store the data to (default: data_%%i.csv)" msgstr "" #: ../sdaps/cmdline/csvdata.py:48 msgid "The delimiter used in the CSV file (default ',')" msgstr "" #: ../sdaps/cmdline/csvdata.py:52 ../sdaps/cmdline/report.py:31 #: ../sdaps/cmdline/reporttex.py:52 msgid "Filter to only export a partial dataset." msgstr "" #: ../sdaps/cmdline/csvdata.py:54 msgid "Export images of freeform fields." msgstr "" #: ../sdaps/cmdline/csvdata.py:60 msgid "Export an image for each question that includes all boxes." msgstr "" #: ../sdaps/cmdline/csvdata.py:66 msgid "Export the recognition quality for each checkbox." msgstr "" #: ../sdaps/cmdline/csvdata.py:74 msgid "Import data to from a CSV file." msgstr "" #: ../sdaps/cmdline/csvdata.py:76 msgid "The file to import." msgstr "" #: ../sdaps/cmdline/gui.py:28 msgid "Launch a GUI. You can view and alter the (recognized) answers with it." msgstr "" #: ../sdaps/cmdline/gui.py:29 msgid "" "This command launches a graphical user interface that can\n" " be used to correct answers. You need to run \"recognize\" before using " "it.\n" " " msgstr "" #: ../sdaps/cmdline/gui.py:34 msgid "Filter to only show a partial dataset." msgstr "" #: ../sdaps/cmdline/ids.py:29 msgid "Export and import questionnaire IDs." msgstr "" #: ../sdaps/cmdline/ids.py:30 msgid "" "This command can be used to import and export questionnaire\n" " IDs. It only makes sense in projects where such an ID is printed on the\n" " questionnaire. Note that you can also add IDs by using the stamp " "command,\n" " which will give you the PDF at the same time." msgstr "" #: ../sdaps/cmdline/ids.py:35 #, python-format msgid "Filename to store the data to (default: ids_%%i)" msgstr "" #: ../sdaps/cmdline/ids.py:38 msgid "Add IDs to the internal list from the specified file." msgstr "" #: ../sdaps/cmdline/info.py:28 msgid "Display and modify metadata of project." msgstr "" #: ../sdaps/cmdline/info.py:29 msgid "" "This command lets you modify the metadata of the SDAPS\n" " project. You can modify, add and remove arbitrary keys that will be " "printed\n" " on the report. The only key that always exist is \"title\".\n" " If no key is given then a list of defined keys is printed." msgstr "" #: ../sdaps/cmdline/info.py:36 msgid "Delete the key and value pair." msgstr "" #: ../sdaps/cmdline/info.py:40 msgid "The key to display or modify." msgstr "" #: ../sdaps/cmdline/info.py:44 msgid "Set the given key to this value." msgstr "" #: ../sdaps/cmdline/info.py:69 msgid "Existing fields:\n" msgstr "" #: ../sdaps/cmdline/recognize.py:28 msgid "Run the optical mark recognition." msgstr "" #: ../sdaps/cmdline/recognize.py:29 msgid "" "Iterates over all images and runs the optical mark\n" " recognition. It will reevaluate sheets even if \"recognize\" has " "already\n" " run or manual changes were made." msgstr "" #: ../sdaps/cmdline/recognize.py:34 msgid "" "Only identify the page properties, but don't recognize the checkbox states." msgstr "" #: ../sdaps/cmdline/recognize.py:39 msgid "" "Rerun the recognition for all pages. The default is to skip all pages that " "were recognized or verified already." msgstr "" #: ../sdaps/cmdline/reorder.py:26 msgid "Reorder pages according to questionnaire ID." msgstr "" #: ../sdaps/cmdline/reorder.py:27 msgid "" "This command reorders all pages according to the already\n" " recognized questionnaire ID. To use it add all the files to the " "project,\n" " then run a partial recognition using \"recognize --identify\". After " "this\n" " you have to run this command to reorder the data for the real " "recognition.\n" " " msgstr "" #: ../sdaps/cmdline/report.py:26 msgid "Create a PDF report." msgstr "" #: ../sdaps/cmdline/report.py:27 msgid "" "This command creates a PDF report using reportlab that\n" " contains statistics and if selected the freeform fields." msgstr "" #: ../sdaps/cmdline/report.py:33 msgid "Create a filtered report for every checkbox." msgstr "" #: ../sdaps/cmdline/report.py:36 msgid "Short format (without freeform text fields)." msgstr "" #: ../sdaps/cmdline/report.py:41 msgid "Detailed output. (default)" msgstr "" #: ../sdaps/cmdline/report.py:47 ../sdaps/cmdline/reporttex.py:30 msgid "" "Do not include original images in the report. This is useful if there are " "privacy concerns." msgstr "" #: ../sdaps/cmdline/report.py:52 ../sdaps/cmdline/reporttex.py:35 msgid "Do not use substitutions instead of images." msgstr "" #: ../sdaps/cmdline/report.py:58 ../sdaps/cmdline/reporttex.py:46 msgid "The paper size used for the output (default: locale dependent)" msgstr "" #: ../sdaps/cmdline/report.py:61 ../sdaps/cmdline/reporttex.py:49 #, python-format msgid "Filename to store the data to (default: report_%%i.pdf)" msgstr "" #: ../sdaps/cmdline/reporttex.py:26 msgid "Create a PDF report using LaTeX." msgstr "" #: ../sdaps/cmdline/reporttex.py:27 msgid "" "This command creates a PDF report using LaTeX that\n" " contains statistics and freeform fields." msgstr "" #: ../sdaps/cmdline/reporttex.py:41 msgid "Save the generated TeX files instead of the final PDF." msgstr "" #: ../sdaps/cmdline/reset.py:26 msgid "Reset project into original state" msgstr "" #: ../sdaps/cmdline/reset.py:27 msgid "" "This command does a full reset of the project. All data\n" " will be discarded and only the empty project is left.\n" " " msgstr "" #: ../sdaps/cmdline/setup.py:27 msgid "Create a new survey using a LaTeX document." msgstr "" #: ../sdaps/cmdline/setup.py:28 msgid "" "Create a new survey from a LaTeX document. You need to\n" " be using the SDAPS class. All the metadata and options for the project\n" " can be set inside the LaTeX document." msgstr "" #: ../sdaps/cmdline/setup.py:33 msgid "The LaTeX Document" msgstr "" #: ../sdaps/cmdline/setup.py:35 msgid "" "Additional files that are required by the LaTeX document and need to be " "copied into the project directory." msgstr "" #: ../sdaps/cmdline/setup.py:39 msgid "Additional questions that are not part of the questionnaire." msgstr "" #: ../sdaps/cmdline/stamp.py:26 msgid "Add marks for automatic processing." msgstr "" #: ../sdaps/cmdline/stamp.py:27 msgid "" "This command creates the printable document. Depending on\n" " the projects setting you are required to specifiy a source for " "questionnaire\n" " IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:33 msgid "" "If using questionnaire IDs, create N questionnaires with randomized IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:36 msgid "" "If using questionnaire IDs, create questionnaires from the IDs read from the " "specified file." msgstr "" #: ../sdaps/cmdline/stamp.py:39 msgid "If using questionnaire IDs, create questionnaires for all stored IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:42 #, python-format msgid "Filename to store the data to (default: stamp_%%i.pdf)" msgstr "" #: ../sdaps/convert/__init__.py:37 #, python-format msgid "Could not apply 3D-transformation to image '%s', page %i!" msgstr "" #: ../sdaps/cover/__init__.py:40 msgid "SDAPS questionnaire" msgstr "" #: ../sdaps/csvdata/buddies.py:77 #, python-format msgid "Not importing unknown questionnaire ID \"%s\"" msgstr "" #: ../sdaps/gui/__init__.py:59 msgid "" "The survey does not have any images! Please add images (and run recognize) " "before using the GUI." msgstr "" #: ../sdaps/gui/__init__.py:211 msgid "Page|Invalid" msgstr "" #: ../sdaps/gui/__init__.py:214 #, python-format msgid "Page %i" msgid_plural "Page %i" msgstr[0] "" msgstr[1] "" #: ../sdaps/gui/__init__.py:256 msgid "Copyright © 2007-2014 The SDAPS Authors" msgstr "" #: ../sdaps/gui/__init__.py:258 msgid "Scripts for data acquisition with paper based surveys" msgstr "" #: ../sdaps/gui/__init__.py:259 msgid "http://sdaps.org" msgstr "" #: ../sdaps/gui/__init__.py:260 msgid "translator-credits" msgstr "" #: ../sdaps/gui/__init__.py:305 #, python-format msgid " of %i" msgstr "" #: ../sdaps/gui/__init__.py:306 #, python-format msgid "Recognition Quality: %.2f" msgstr "" #: ../sdaps/gui/__init__.py:322 msgid "" "You have reached the first page of the survey. Would you like to go to the " "last page?" msgstr "" #: ../sdaps/gui/__init__.py:324 msgid "Go to last page" msgstr "" #: ../sdaps/gui/__init__.py:346 msgid "" "You have reached the last page of the survey. Would you like to go to the " "first page?" msgstr "" #: ../sdaps/gui/__init__.py:348 msgid "Go to first page" msgstr "" #: ../sdaps/gui/__init__.py:457 msgid "Close without saving" msgstr "" #: ../sdaps/gui/__init__.py:461 msgid "" "Save the project before closing?\n" "\n" "If you do not save you may loose data." msgstr "" #: ../sdaps/gui/main_window.ui.h:1 msgid "Forward" msgstr "" #: ../sdaps/gui/main_window.ui.h:2 msgid "Previous" msgstr "" #: ../sdaps/gui/main_window.ui.h:3 msgid "Zoom In" msgstr "" #: ../sdaps/gui/main_window.ui.h:4 msgid "Zoom Out" msgstr "" #: ../sdaps/gui/main_window.ui.h:5 msgid "SDAPS" msgstr "" #: ../sdaps/gui/main_window.ui.h:6 msgid "_File" msgstr "" #: ../sdaps/gui/main_window.ui.h:7 msgid "_View" msgstr "" #: ../sdaps/gui/main_window.ui.h:8 msgid "_Help" msgstr "" #: ../sdaps/gui/main_window.ui.h:9 msgid "Page Rotated" msgstr "" #: ../sdaps/gui/main_window.ui.h:10 msgid "Sort by Quality" msgstr "" #: ../sdaps/gui/main_window.ui.h:11 msgid "label" msgstr "" #: ../sdaps/gui/widget_buddies.py:56 msgid "Global Properties" msgstr "" #: ../sdaps/gui/widget_buddies.py:60 msgid "Sheet valid" msgstr "" #: ../sdaps/gui/widget_buddies.py:61 msgid "Sheet Verified" msgstr "" #: ../sdaps/gui/widget_buddies.py:62 msgid "Page Verified" msgstr "" #: ../sdaps/gui/widget_buddies.py:63 msgid "Empty" msgstr "" #: ../sdaps/gui/widget_buddies.py:75 ../sdaps/gui/widget_buddies.py:105 msgid "Questionnaire ID: " msgstr "" #: ../sdaps/image/__init__.py:47 msgid "" "It appears you have not build the C extension. Please run \"./setup.py build" "\" in the toplevel directory." msgstr "" #: ../sdaps/utils/latex.py:29 msgid "" "The latex character map is missing! Please build it using the supplied tool " "(create-latexmap.py)." msgstr "" #: ../sdaps/utils/latex.py:69 msgid "" "Generated string for LaTeX contains unicode characters. This may not work " "correctly and could mean the LaTeX character map needs to be updated." msgstr "" #: ../sdaps/utils/opencv.py:35 msgid "Cannot convert PDF files as poppler is not installed or usable!" msgstr "" #: ../sdaps/utils/opencv.py:44 msgid "File does not exist" msgstr "" #. The old code used to first filter, and then run; but that is #. a bit ineffective in a way #: ../sdaps/model/survey.py:386 #, python-format msgid "%i sheet" msgid_plural "%i sheets" msgstr[0] "" msgstr[1] "" #: ../sdaps/model/survey.py:402 #, python-format msgid "Processed %i of %i sheets, took %f seconds" msgstr "" #: ../sdaps/model/survey.py:449 msgid "" "A questionnaire that is printed in duplex needs an even amount of pages!" msgstr "" #: ../sdaps/model/survey.py:453 msgid "" "The 'classic' style only supports a maximum of six pages! Use the 'code128' " "style if you require more pages." msgstr "" #: ../sdaps/model/survey.py:466 msgid "IDs need to be integers in \"classic\" style!" msgstr "" #: ../sdaps/model/survey.py:472 #, python-format msgid "Invalid character %s in questionnaire ID \"%s\" in \"code128\" style!" msgstr "" #: ../sdaps/model/survey.py:476 msgid "" "SDAPS cannot draw a questionnaire ID with the \"custom\" style. Do this " "yourself somehow!" msgstr "" #. in simplex mode every page will have a matrix; it might be a None #. matrix though #: ../sdaps/recognize/buddies.py:71 #, python-format msgid "%s, %i: Matrix not recognized." msgstr "" #: ../sdaps/recognize/buddies.py:80 #, python-format msgid "%s, %i: Rotation not found." msgstr "" #. Copy the rotation over (if required) and print warning if the rotation is unknown #: ../sdaps/recognize/buddies.py:84 #, python-format msgid "Neither %s, %i or %s, %i has a known rotation!" msgstr "" #: ../sdaps/recognize/buddies.py:96 #, python-format msgid "%s, %i: Matrix not recognized (again)." msgstr "" #: ../sdaps/recognize/buddies.py:110 #, python-format msgid "%s, %i: Could not get page number." msgstr "" #. Whoa, that should not happen. #: ../sdaps/recognize/buddies.py:130 #, python-format msgid "Neither %s, %i or %s, %i has a known page number!" msgstr "" #. We don't touch the ignore flag in this case #. Simply print a message as this should *never* happen #: ../sdaps/recognize/buddies.py:141 #, python-format msgid "" "Got a simplex document where two adjacent pages had a known page number. " "This should never happen as even simplex scans are converted to duplex by " "inserting dummy pages. Maybe you did a simplex scan but added it in duplex " "mode? The pages in question are %s, %i and %s, %i." msgstr "" #: ../sdaps/recognize/buddies.py:158 #, python-format msgid "Images %s, %i and %s, %i do not have consecutive page numbers!" msgstr "" #: ../sdaps/recognize/buddies.py:174 #, python-format msgid "No page number for page %s, %i exists." msgstr "" #: ../sdaps/recognize/buddies.py:179 #, python-format msgid "Page number for page %s, %i already used by another image." msgstr "" #: ../sdaps/recognize/buddies.py:185 #, python-format msgid "Page number %i for page %s, %i is out of range." msgstr "" #: ../sdaps/recognize/buddies.py:202 #, python-format msgid "%s, %i: Could not read survey ID, but should be able to." msgstr "" #: ../sdaps/recognize/buddies.py:206 #, python-format msgid "Could not read survey ID of either %s, %i or %s, %i!" msgstr "" #. Broken survey ID ... #: ../sdaps/recognize/buddies.py:213 #, python-format msgid "Got a wrong survey ID (%s, %i)! It is %s, but should be %i." msgstr "" #: ../sdaps/recognize/buddies.py:235 #, python-format msgid "%s, %i: Could not read questionnaire ID, but should be able to." msgstr "" #: ../sdaps/recognize/buddies.py:241 #, python-format msgid "Could not read questionnaire ID of either %s, %i or %s, %i!" msgstr "" #: ../sdaps/recognize/buddies.py:271 msgid "" "Got different IDs on different pages for at least one sheet! Do *NOT* try to " "use filters with this survey! You have to run a \"reorder\" step for this to " "work properly!" msgstr "" #: ../sdaps/recognize/buddies.py:326 msgid "No style buddy loaded. This needs to be done for the \"custom\" style!" msgstr "" #: ../sdaps/report/answers.py:188 #, python-format msgid "Answers: %i" msgstr "" #: ../sdaps/report/answers.py:190 #, python-format msgid "Mean: %.2f" msgstr "" #: ../sdaps/report/answers.py:192 #, python-format msgid "Standard Deviation: %.2f" msgstr "" #: ../sdaps/report/__init__.py:75 ../sdaps/reporttex/__init__.py:140 msgid "Turned in Questionnaires" msgstr "" #: ../sdaps/report/__init__.py:92 ../sdaps/reporttex/__init__.py:139 msgid "sdaps report" msgstr "" #: ../sdaps/reset/__init__.py:29 msgid "Removing stored data..." msgstr "" #: ../sdaps/setup/buddies.py:62 #, python-format msgid "Head %(l0)i got no title." msgstr "" #: ../sdaps/setup/buddies.py:74 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no question." msgstr "" #: ../sdaps/setup/buddies.py:114 #, python-format msgid "Error in question \"%s\"" msgstr "" #: ../sdaps/setup/buddies.py:118 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no boxes." msgstr "" #: ../sdaps/setup/buddies.py:167 #, python-format msgid "%(class)s %(l0)i.%(l1)i lower box out of range." msgstr "" #: ../sdaps/setup/buddies.py:172 #, python-format msgid "%(class)s %(l0)i.%(l1)i upper box out of range." msgstr "" #: ../sdaps/setup/buddies.py:177 #, python-format msgid "%(class)s %(l0)i.%(l1)i lower box not before upper box." msgstr "" #: ../sdaps/setup/buddies.py:213 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly two answers." msgstr "" #: ../sdaps/setup/buddies.py:234 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly one box." msgstr "" #: ../sdaps/stamp/__init__.py:38 msgid "" "You may not specify the number of sheets for this survey. All questionnaires " "will be identical as the survey has been configured to not use questionnaire " "IDs for each sheet." msgstr "" #: ../sdaps/stamp/__init__.py:76 msgid "" "This survey has been configured to use questionnaire IDs. Each questionnaire " "will be unique. You need to use on of the options to add new IDs or use the " "existing ones." msgstr "" #: ../sdaps/stamp/latex.py:18 msgid "" "There should be no need to stamp a SDAPS Project that uses LaTeX and does " "not have different questionnaire IDs printed on each sheet.\n" "I am going to do so anyways." msgstr "" #: ../sdaps/stamp/latex.py:26 #, python-format msgid "Running %s now twice to generate the stamped questionnaire." msgstr "" #: ../sdaps/stamp/latex.py:30 ../sdaps/setuptex/__init__.py:107 #: ../sdaps/setuptex/__init__.py:148 ../sdaps/reporttex/__init__.py:162 #, python-format msgid "Error running \"%s\" to compile the LaTeX file." msgstr "" #: ../sdaps/stamp/latex.py:36 #, python-format msgid "" "An error occured during creation of the report. Temporary files left in '%s'." msgstr "" #: ../sdaps/setuptex/__init__.py:46 msgid "The survey directory already exists." msgstr "" #: ../sdaps/setuptex/__init__.py:51 #, python-format msgid "Unknown file type (%s). questionnaire_tex should be of type text/x-tex." msgstr "" #: ../sdaps/setuptex/__init__.py:52 msgid "Will keep going, but expect failure!" msgstr "" #: ../sdaps/setuptex/__init__.py:57 #, python-format msgid "Unknown file type (%s). additionalqobjects should be text/plain." msgstr "" #: ../sdaps/setuptex/__init__.py:103 ../sdaps/setuptex/__init__.py:143 #, python-format msgid "Running %s now twice to generate the questionnaire." msgstr "" #: ../sdaps/setuptex/__init__.py:122 msgid "Caught an Exception while parsing the SDAPS file. The current state is:" msgstr "" #: ../sdaps/setuptex/__init__.py:136 msgid "" "Some combination of options and project properties do not work. Aborted " "Setup." msgstr "" #: ../sdaps/setuptex/__init__.py:162 msgid "" "An error occured in the setup routine. The survey directory still exists. " "You can for example check the questionnaire.log file for LaTeX compile " "errors." msgstr "" #: ../sdaps/reporttex/__init__.py:107 msgid "author|Unknown" msgstr "" #: ../sdaps/reporttex/__init__.py:138 msgid "tex language|english" msgstr "" #: ../sdaps/reporttex/__init__.py:155 #, python-format msgid "The TeX project with the report data is located at '%s'." msgstr "" #: ../sdaps/reporttex/__init__.py:158 #, python-format msgid "Running %s now twice to generate the report." msgstr "" #: ../sdaps/reporttex/__init__.py:168 #, python-format msgid "An occured during creation of the report. Temporary files left in '%s'." msgstr "" sdaps-1.9.8/po/uk.po0000644000175000000660000006114113410742232014775 0ustar benjaminlock00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:10+0100\n" "PO-Revision-Date: 2018-01-31 17:40+0000\n" "Last-Translator: Марс Ямбар \n" "Language-Team: Ukrainian \n" "Language: uk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" "X-Generator: Weblate 2.19-dev\n" #: ../sdaps/script.py:41 msgid "SDAPS -- Paper based survey tool." msgstr "" #: ../sdaps/script.py:45 msgid "command list|Commands:" msgstr "Список команд|Команди:" #: ../sdaps/script.py:50 msgid "project directory|The SDAPS project." msgstr "" #: ../sdaps/add/__init__.py:55 #, python-format msgid "" "Invalid input file %s. You need to specify a (multipage) monochrome TIFF as " "input." msgstr "" #: ../sdaps/add/__init__.py:67 #, python-format msgid "" "Not adding %s because it has a wrong page count (needs to be a mulitple of " "%i)." msgstr "" #: ../sdaps/boxgallery/__init__.py:108 #, python-format msgid "Rendering boxgallery for metric \"%s\"." msgstr "" #: ../sdaps/log.py:37 msgid "Warning: " msgstr "" #: ../sdaps/log.py:41 msgid "Error: " msgstr "" #: ../sdaps/cmdline/add.py:31 msgid "Add scanned questionnaires to the survey." msgstr "" #: ../sdaps/cmdline/add.py:32 msgid "" "This command is used to add scanned images to the survey.\n" " The image data needs to be a (multipage) 300dpi monochrome TIFF file. " "You\n" " may choose not to copy the data into the project directory. In that " "case\n" " the data will be referenced using a relative path." msgstr "" #: ../sdaps/cmdline/add.py:38 msgid "Convert given files and add the result." msgstr "" #: ../sdaps/cmdline/add.py:43 msgid "" "Do a 3D-transformation after finding the corner marks. If the\n" " corner marks are not found then the image will be added as-is." msgstr "" #: ../sdaps/cmdline/add.py:49 msgid "" "Force adding the images even if the page count is wrong (only use if you " "know what you are doing)." msgstr "" #: ../sdaps/cmdline/add.py:53 msgid "Copy the files into the directory (default)." msgstr "" #: ../sdaps/cmdline/add.py:58 msgid "Do not copy the files into the directory." msgstr "" #: ../sdaps/cmdline/add.py:62 msgid "" "Images contain a duplex scan of a simplex questionnaire (default: simplex " "scan)." msgstr "" #: ../sdaps/cmdline/add.py:68 ../sdaps/cmdline/convert.py:48 msgid "A number of TIFF image files." msgstr "" #: ../sdaps/cmdline/add.py:94 msgid "The --no-copy option is not compatible with --convert!" msgstr "" #: ../sdaps/cmdline/add.py:103 msgid "Converting input files into a single temporary file." msgstr "" #: ../sdaps/cmdline/add.py:115 msgid "" "The page count of the created temporary file does not work with this survey." msgstr "" #: ../sdaps/cmdline/add.py:120 msgid "Running the conversion failed." msgstr "" #: ../sdaps/cmdline/add.py:126 #, python-format msgid "Processing %s" msgstr "" #: ../sdaps/cmdline/add.py:130 ../sdaps/reset/__init__.py:33 msgid "Done" msgstr "" #: ../sdaps/cmdline/annotate.py:28 msgid "Annotate the questionnaire and show the recognized positions." msgstr "" #: ../sdaps/cmdline/annotate.py:29 msgid "" "This command is mainly a debug utility. It creates an\n" " annotated version of the questionnaire, with the information that SDAPS\n" " knows about it overlayed on top." msgstr "" #: ../sdaps/cmdline/boxgallery.py:31 msgid "Create PDFs with boxes sorted by the detection heuristics." msgstr "" #: ../sdaps/cmdline/boxgallery.py:32 msgid "" "SDAPS uses multiple heuristics to detect determine the\n" " state of checkboxes. There is a list for each heuristic giving the " "expected\n" " state and the quality of the value (see defs.py). Using this command a " "PDF\n" " will be created for each of the heuristics so that one can adjust the\n" " values." msgstr "" #: ../sdaps/cmdline/boxgallery.py:40 msgid "" "Reruns part of the recognition process and retrieves debug images from this " "step." msgstr "" #: ../sdaps/cmdline/convert.py:30 msgid "Convert a set of images to the correct image format." msgstr "" #: ../sdaps/cmdline/convert.py:31 msgid "" "This command can be used if you scanned files in something\n" " other than the expected monochrome TIFF mode. All given files will\n" " be loaded, converted to monochrome and stored in a multipage 1bpp\n" " TIFF file. Optionally, you can select \"3D transformation\"\\ ,which " "may facilitate\n" " working with photos of questionnaires instead of scans." msgstr "" #: ../sdaps/cmdline/convert.py:38 msgid "" "Do a 3D-transformation after finding the corner marks.\n" " If they are not found, the image will be processed as-is." msgstr "" #: ../sdaps/cmdline/convert.py:44 msgid "The location of the output file." msgstr "" #: ../sdaps/cmdline/convert.py:57 msgid "No output filename specified!" msgstr "" #: ../sdaps/cmdline/cover.py:27 msgid "Create a cover for the questionnaires." msgstr "" #: ../sdaps/cmdline/cover.py:28 msgid "" "This command creates a cover page for questionnaires. All\n" " the metadata of the survey will be printed on the page." msgstr "" #: ../sdaps/cmdline/cover.py:31 #, python-format msgid "Filename to store the data to (default: cover_%%i.pdf)" msgstr "" #: ../sdaps/cmdline/csvdata.py:34 msgid "Import or export data to/from CSV files." msgstr "" #: ../sdaps/cmdline/csvdata.py:35 msgid "" "Import or export data to/from a CSV file. The first line\n" " is a header which defines questionnaire_id and global_id, and a column\n" " for each checkbox and textfield. Note that the import is currently very\n" " limited, as you need to specifiy the questionnaire ID to select the " "sheet\n" " which should be updated." msgstr "" #: ../sdaps/cmdline/csvdata.py:44 msgid "Export data to CSV file." msgstr "" #: ../sdaps/cmdline/csvdata.py:46 #, python-format msgid "Filename to store the data to (default: data_%%i.csv)" msgstr "" #: ../sdaps/cmdline/csvdata.py:48 msgid "The delimiter used in the CSV file (default ',')" msgstr "" #: ../sdaps/cmdline/csvdata.py:52 ../sdaps/cmdline/report.py:31 #: ../sdaps/cmdline/reporttex.py:52 msgid "Filter to only export a partial dataset." msgstr "" #: ../sdaps/cmdline/csvdata.py:54 msgid "Export images of freeform fields." msgstr "" #: ../sdaps/cmdline/csvdata.py:60 msgid "Export an image for each question that includes all boxes." msgstr "" #: ../sdaps/cmdline/csvdata.py:66 msgid "Export the recognition quality for each checkbox." msgstr "" #: ../sdaps/cmdline/csvdata.py:74 msgid "Import data to from a CSV file." msgstr "" #: ../sdaps/cmdline/csvdata.py:76 msgid "The file to import." msgstr "" #: ../sdaps/cmdline/gui.py:28 msgid "Launch a GUI. You can view and alter the (recognized) answers with it." msgstr "" #: ../sdaps/cmdline/gui.py:29 msgid "" "This command launches a graphical user interface that can\n" " be used to correct answers. You need to run \"recognize\" before using " "it.\n" " " msgstr "" #: ../sdaps/cmdline/gui.py:34 msgid "Filter to only show a partial dataset." msgstr "" #: ../sdaps/cmdline/ids.py:29 msgid "Export and import questionnaire IDs." msgstr "" #: ../sdaps/cmdline/ids.py:30 msgid "" "This command can be used to import and export questionnaire\n" " IDs. It only makes sense in projects where such an ID is printed on the\n" " questionnaire. Note that you can also add IDs by using the stamp " "command,\n" " which will give you the PDF at the same time." msgstr "" #: ../sdaps/cmdline/ids.py:35 #, python-format msgid "Filename to store the data to (default: ids_%%i)" msgstr "" #: ../sdaps/cmdline/ids.py:38 msgid "Add IDs to the internal list from the specified file." msgstr "" #: ../sdaps/cmdline/info.py:28 msgid "Display and modify metadata of project." msgstr "" #: ../sdaps/cmdline/info.py:29 msgid "" "This command lets you modify the metadata of the SDAPS\n" " project. You can modify, add and remove arbitrary keys that will be " "printed\n" " on the report. The only key that always exist is \"title\".\n" " If no key is given then a list of defined keys is printed." msgstr "" #: ../sdaps/cmdline/info.py:36 msgid "Delete the key and value pair." msgstr "" #: ../sdaps/cmdline/info.py:40 msgid "The key to display or modify." msgstr "" #: ../sdaps/cmdline/info.py:44 msgid "Set the given key to this value." msgstr "" #: ../sdaps/cmdline/info.py:69 msgid "Existing fields:\n" msgstr "" #: ../sdaps/cmdline/recognize.py:28 msgid "Run the optical mark recognition." msgstr "" #: ../sdaps/cmdline/recognize.py:29 msgid "" "Iterates over all images and runs the optical mark\n" " recognition. It will reevaluate sheets even if \"recognize\" has " "already\n" " run or manual changes were made." msgstr "" #: ../sdaps/cmdline/recognize.py:34 msgid "" "Only identify the page properties, but don't recognize the checkbox states." msgstr "" #: ../sdaps/cmdline/recognize.py:39 msgid "" "Rerun the recognition for all pages. The default is to skip all pages that " "were recognized or verified already." msgstr "" #: ../sdaps/cmdline/reorder.py:26 msgid "Reorder pages according to questionnaire ID." msgstr "" #: ../sdaps/cmdline/reorder.py:27 msgid "" "This command reorders all pages according to the already\n" " recognized questionnaire ID. To use it add all the files to the " "project,\n" " then run a partial recognition using \"recognize --identify\". After " "this\n" " you have to run this command to reorder the data for the real " "recognition.\n" " " msgstr "" #: ../sdaps/cmdline/report.py:26 msgid "Create a PDF report." msgstr "" #: ../sdaps/cmdline/report.py:27 msgid "" "This command creates a PDF report using reportlab that\n" " contains statistics and if selected the freeform fields." msgstr "" #: ../sdaps/cmdline/report.py:33 msgid "Create a filtered report for every checkbox." msgstr "" #: ../sdaps/cmdline/report.py:36 msgid "Short format (without freeform text fields)." msgstr "" #: ../sdaps/cmdline/report.py:41 msgid "Detailed output. (default)" msgstr "" #: ../sdaps/cmdline/report.py:47 ../sdaps/cmdline/reporttex.py:30 msgid "" "Do not include original images in the report. This is useful if there are " "privacy concerns." msgstr "" #: ../sdaps/cmdline/report.py:52 ../sdaps/cmdline/reporttex.py:35 msgid "Do not use substitutions instead of images." msgstr "" #: ../sdaps/cmdline/report.py:58 ../sdaps/cmdline/reporttex.py:46 msgid "The paper size used for the output (default: locale dependent)" msgstr "" #: ../sdaps/cmdline/report.py:61 ../sdaps/cmdline/reporttex.py:49 #, python-format msgid "Filename to store the data to (default: report_%%i.pdf)" msgstr "" #: ../sdaps/cmdline/reporttex.py:26 msgid "Create a PDF report using LaTeX." msgstr "" #: ../sdaps/cmdline/reporttex.py:27 msgid "" "This command creates a PDF report using LaTeX that\n" " contains statistics and freeform fields." msgstr "" #: ../sdaps/cmdline/reporttex.py:41 msgid "Save the generated TeX files instead of the final PDF." msgstr "" #: ../sdaps/cmdline/reset.py:26 msgid "Reset project into original state" msgstr "" #: ../sdaps/cmdline/reset.py:27 msgid "" "This command does a full reset of the project. All data\n" " will be discarded and only the empty project is left.\n" " " msgstr "" #: ../sdaps/cmdline/setup.py:27 msgid "Create a new survey using a LaTeX document." msgstr "" #: ../sdaps/cmdline/setup.py:28 msgid "" "Create a new survey from a LaTeX document. You need to\n" " be using the SDAPS class. All the metadata and options for the project\n" " can be set inside the LaTeX document." msgstr "" #: ../sdaps/cmdline/setup.py:33 msgid "The LaTeX Document" msgstr "" #: ../sdaps/cmdline/setup.py:35 msgid "" "Additional files that are required by the LaTeX document and need to be " "copied into the project directory." msgstr "" #: ../sdaps/cmdline/setup.py:39 msgid "Additional questions that are not part of the questionnaire." msgstr "" #: ../sdaps/cmdline/stamp.py:26 msgid "Add marks for automatic processing." msgstr "" #: ../sdaps/cmdline/stamp.py:27 msgid "" "This command creates the printable document. Depending on\n" " the projects setting you are required to specifiy a source for " "questionnaire\n" " IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:33 msgid "" "If using questionnaire IDs, create N questionnaires with randomized IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:36 msgid "" "If using questionnaire IDs, create questionnaires from the IDs read from the " "specified file." msgstr "" #: ../sdaps/cmdline/stamp.py:39 msgid "If using questionnaire IDs, create questionnaires for all stored IDs." msgstr "" #: ../sdaps/cmdline/stamp.py:42 #, python-format msgid "Filename to store the data to (default: stamp_%%i.pdf)" msgstr "" #: ../sdaps/convert/__init__.py:37 #, python-format msgid "Could not apply 3D-transformation to image '%s', page %i!" msgstr "" #: ../sdaps/cover/__init__.py:40 msgid "SDAPS questionnaire" msgstr "" #: ../sdaps/csvdata/buddies.py:77 #, python-format msgid "Not importing unknown questionnaire ID \"%s\"" msgstr "" #: ../sdaps/gui/__init__.py:59 msgid "" "The survey does not have any images! Please add images (and run recognize) " "before using the GUI." msgstr "" #: ../sdaps/gui/__init__.py:211 msgid "Page|Invalid" msgstr "" #: ../sdaps/gui/__init__.py:214 #, python-format msgid "Page %i" msgid_plural "Page %i" msgstr[0] "" msgstr[1] "" #: ../sdaps/gui/__init__.py:256 msgid "Copyright © 2007-2014 The SDAPS Authors" msgstr "" #: ../sdaps/gui/__init__.py:258 msgid "Scripts for data acquisition with paper based surveys" msgstr "" #: ../sdaps/gui/__init__.py:259 msgid "http://sdaps.org" msgstr "" #: ../sdaps/gui/__init__.py:260 msgid "translator-credits" msgstr "" #: ../sdaps/gui/__init__.py:305 #, python-format msgid " of %i" msgstr "" #: ../sdaps/gui/__init__.py:306 #, python-format msgid "Recognition Quality: %.2f" msgstr "" #: ../sdaps/gui/__init__.py:322 msgid "" "You have reached the first page of the survey. Would you like to go to the " "last page?" msgstr "" #: ../sdaps/gui/__init__.py:324 msgid "Go to last page" msgstr "" #: ../sdaps/gui/__init__.py:346 msgid "" "You have reached the last page of the survey. Would you like to go to the " "first page?" msgstr "" #: ../sdaps/gui/__init__.py:348 msgid "Go to first page" msgstr "" #: ../sdaps/gui/__init__.py:457 msgid "Close without saving" msgstr "" #: ../sdaps/gui/__init__.py:461 msgid "" "Save the project before closing?\n" "\n" "If you do not save you may loose data." msgstr "" #: ../sdaps/gui/main_window.ui.h:1 msgid "Forward" msgstr "" #: ../sdaps/gui/main_window.ui.h:2 msgid "Previous" msgstr "" #: ../sdaps/gui/main_window.ui.h:3 msgid "Zoom In" msgstr "" #: ../sdaps/gui/main_window.ui.h:4 msgid "Zoom Out" msgstr "" #: ../sdaps/gui/main_window.ui.h:5 msgid "SDAPS" msgstr "" #: ../sdaps/gui/main_window.ui.h:6 msgid "_File" msgstr "" #: ../sdaps/gui/main_window.ui.h:7 msgid "_View" msgstr "" #: ../sdaps/gui/main_window.ui.h:8 msgid "_Help" msgstr "" #: ../sdaps/gui/main_window.ui.h:9 msgid "Page Rotated" msgstr "" #: ../sdaps/gui/main_window.ui.h:10 msgid "Sort by Quality" msgstr "" #: ../sdaps/gui/main_window.ui.h:11 msgid "label" msgstr "" #: ../sdaps/gui/widget_buddies.py:56 msgid "Global Properties" msgstr "" #: ../sdaps/gui/widget_buddies.py:60 msgid "Sheet valid" msgstr "" #: ../sdaps/gui/widget_buddies.py:61 msgid "Sheet Verified" msgstr "" #: ../sdaps/gui/widget_buddies.py:62 msgid "Page Verified" msgstr "" #: ../sdaps/gui/widget_buddies.py:63 msgid "Empty" msgstr "" #: ../sdaps/gui/widget_buddies.py:75 ../sdaps/gui/widget_buddies.py:105 msgid "Questionnaire ID: " msgstr "" #: ../sdaps/image/__init__.py:47 msgid "" "It appears you have not build the C extension. Please run \"./setup.py build" "\" in the toplevel directory." msgstr "" #: ../sdaps/utils/latex.py:29 msgid "" "The latex character map is missing! Please build it using the supplied tool " "(create-latexmap.py)." msgstr "" #: ../sdaps/utils/latex.py:69 msgid "" "Generated string for LaTeX contains unicode characters. This may not work " "correctly and could mean the LaTeX character map needs to be updated." msgstr "" #: ../sdaps/utils/opencv.py:35 msgid "Cannot convert PDF files as poppler is not installed or usable!" msgstr "" #: ../sdaps/utils/opencv.py:44 msgid "File does not exist" msgstr "" #. The old code used to first filter, and then run; but that is #. a bit ineffective in a way #: ../sdaps/model/survey.py:386 #, python-format msgid "%i sheet" msgid_plural "%i sheets" msgstr[0] "" msgstr[1] "" #: ../sdaps/model/survey.py:402 #, python-format msgid "Processed %i of %i sheets, took %f seconds" msgstr "" #: ../sdaps/model/survey.py:449 msgid "" "A questionnaire that is printed in duplex needs an even amount of pages!" msgstr "" #: ../sdaps/model/survey.py:453 msgid "" "The 'classic' style only supports a maximum of six pages! Use the 'code128' " "style if you require more pages." msgstr "" #: ../sdaps/model/survey.py:466 msgid "IDs need to be integers in \"classic\" style!" msgstr "" #: ../sdaps/model/survey.py:472 #, python-format msgid "Invalid character %s in questionnaire ID \"%s\" in \"code128\" style!" msgstr "" #: ../sdaps/model/survey.py:476 msgid "" "SDAPS cannot draw a questionnaire ID with the \"custom\" style. Do this " "yourself somehow!" msgstr "" #. in simplex mode every page will have a matrix; it might be a None #. matrix though #: ../sdaps/recognize/buddies.py:71 #, python-format msgid "%s, %i: Matrix not recognized." msgstr "" #: ../sdaps/recognize/buddies.py:80 #, python-format msgid "%s, %i: Rotation not found." msgstr "" #. Copy the rotation over (if required) and print warning if the rotation is unknown #: ../sdaps/recognize/buddies.py:84 #, python-format msgid "Neither %s, %i or %s, %i has a known rotation!" msgstr "" #: ../sdaps/recognize/buddies.py:96 #, python-format msgid "%s, %i: Matrix not recognized (again)." msgstr "" #: ../sdaps/recognize/buddies.py:110 #, python-format msgid "%s, %i: Could not get page number." msgstr "" #. Whoa, that should not happen. #: ../sdaps/recognize/buddies.py:130 #, python-format msgid "Neither %s, %i or %s, %i has a known page number!" msgstr "" #. We don't touch the ignore flag in this case #. Simply print a message as this should *never* happen #: ../sdaps/recognize/buddies.py:141 #, python-format msgid "" "Got a simplex document where two adjacent pages had a known page number. " "This should never happen as even simplex scans are converted to duplex by " "inserting dummy pages. Maybe you did a simplex scan but added it in duplex " "mode? The pages in question are %s, %i and %s, %i." msgstr "" #: ../sdaps/recognize/buddies.py:158 #, python-format msgid "Images %s, %i and %s, %i do not have consecutive page numbers!" msgstr "" #: ../sdaps/recognize/buddies.py:174 #, python-format msgid "No page number for page %s, %i exists." msgstr "" #: ../sdaps/recognize/buddies.py:179 #, python-format msgid "Page number for page %s, %i already used by another image." msgstr "" #: ../sdaps/recognize/buddies.py:185 #, python-format msgid "Page number %i for page %s, %i is out of range." msgstr "" #: ../sdaps/recognize/buddies.py:202 #, python-format msgid "%s, %i: Could not read survey ID, but should be able to." msgstr "" #: ../sdaps/recognize/buddies.py:206 #, python-format msgid "Could not read survey ID of either %s, %i or %s, %i!" msgstr "" #. Broken survey ID ... #: ../sdaps/recognize/buddies.py:213 #, python-format msgid "Got a wrong survey ID (%s, %i)! It is %s, but should be %i." msgstr "" #: ../sdaps/recognize/buddies.py:235 #, python-format msgid "%s, %i: Could not read questionnaire ID, but should be able to." msgstr "" #: ../sdaps/recognize/buddies.py:241 #, python-format msgid "Could not read questionnaire ID of either %s, %i or %s, %i!" msgstr "" #: ../sdaps/recognize/buddies.py:271 msgid "" "Got different IDs on different pages for at least one sheet! Do *NOT* try to " "use filters with this survey! You have to run a \"reorder\" step for this to " "work properly!" msgstr "" #: ../sdaps/recognize/buddies.py:326 msgid "No style buddy loaded. This needs to be done for the \"custom\" style!" msgstr "" #: ../sdaps/report/answers.py:188 #, python-format msgid "Answers: %i" msgstr "" #: ../sdaps/report/answers.py:190 #, python-format msgid "Mean: %.2f" msgstr "" #: ../sdaps/report/answers.py:192 #, python-format msgid "Standard Deviation: %.2f" msgstr "" #: ../sdaps/report/__init__.py:75 ../sdaps/reporttex/__init__.py:140 msgid "Turned in Questionnaires" msgstr "" #: ../sdaps/report/__init__.py:92 ../sdaps/reporttex/__init__.py:139 msgid "sdaps report" msgstr "" #: ../sdaps/reset/__init__.py:29 msgid "Removing stored data..." msgstr "" #: ../sdaps/setup/buddies.py:62 #, python-format msgid "Head %(l0)i got no title." msgstr "" #: ../sdaps/setup/buddies.py:74 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no question." msgstr "" #: ../sdaps/setup/buddies.py:114 #, python-format msgid "Error in question \"%s\"" msgstr "" #: ../sdaps/setup/buddies.py:118 #, python-format msgid "%(class)s %(l0)i.%(l1)i got no boxes." msgstr "" #: ../sdaps/setup/buddies.py:167 #, python-format msgid "%(class)s %(l0)i.%(l1)i lower box out of range." msgstr "" #: ../sdaps/setup/buddies.py:172 #, python-format msgid "%(class)s %(l0)i.%(l1)i upper box out of range." msgstr "" #: ../sdaps/setup/buddies.py:177 #, python-format msgid "%(class)s %(l0)i.%(l1)i lower box not before upper box." msgstr "" #: ../sdaps/setup/buddies.py:213 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly two answers." msgstr "" #: ../sdaps/setup/buddies.py:234 #, python-format msgid "%(class)s %(l0)i.%(l1)i got not exactly one box." msgstr "" #: ../sdaps/stamp/__init__.py:38 msgid "" "You may not specify the number of sheets for this survey. All questionnaires " "will be identical as the survey has been configured to not use questionnaire " "IDs for each sheet." msgstr "" #: ../sdaps/stamp/__init__.py:76 msgid "" "This survey has been configured to use questionnaire IDs. Each questionnaire " "will be unique. You need to use on of the options to add new IDs or use the " "existing ones." msgstr "" #: ../sdaps/stamp/latex.py:18 msgid "" "There should be no need to stamp a SDAPS Project that uses LaTeX and does " "not have different questionnaire IDs printed on each sheet.\n" "I am going to do so anyways." msgstr "" #: ../sdaps/stamp/latex.py:26 #, python-format msgid "Running %s now twice to generate the stamped questionnaire." msgstr "" #: ../sdaps/stamp/latex.py:30 ../sdaps/setuptex/__init__.py:107 #: ../sdaps/setuptex/__init__.py:148 ../sdaps/reporttex/__init__.py:162 #, python-format msgid "Error running \"%s\" to compile the LaTeX file." msgstr "" #: ../sdaps/stamp/latex.py:36 #, python-format msgid "" "An error occured during creation of the report. Temporary files left in '%s'." msgstr "" #: ../sdaps/setuptex/__init__.py:46 msgid "The survey directory already exists." msgstr "" #: ../sdaps/setuptex/__init__.py:51 #, python-format msgid "Unknown file type (%s). questionnaire_tex should be of type text/x-tex." msgstr "" #: ../sdaps/setuptex/__init__.py:52 msgid "Will keep going, but expect failure!" msgstr "" #: ../sdaps/setuptex/__init__.py:57 #, python-format msgid "Unknown file type (%s). additionalqobjects should be text/plain." msgstr "" #: ../sdaps/setuptex/__init__.py:103 ../sdaps/setuptex/__init__.py:143 #, python-format msgid "Running %s now twice to generate the questionnaire." msgstr "" #: ../sdaps/setuptex/__init__.py:122 msgid "Caught an Exception while parsing the SDAPS file. The current state is:" msgstr "" #: ../sdaps/setuptex/__init__.py:136 msgid "" "Some combination of options and project properties do not work. Aborted " "Setup." msgstr "" #: ../sdaps/setuptex/__init__.py:162 msgid "" "An error occured in the setup routine. The survey directory still exists. " "You can for example check the questionnaire.log file for LaTeX compile " "errors." msgstr "" #: ../sdaps/reporttex/__init__.py:107 msgid "author|Unknown" msgstr "" #: ../sdaps/reporttex/__init__.py:138 msgid "tex language|english" msgstr "" #: ../sdaps/reporttex/__init__.py:155 #, python-format msgid "The TeX project with the report data is located at '%s'." msgstr "" #: ../sdaps/reporttex/__init__.py:158 #, python-format msgid "Running %s now twice to generate the report." msgstr "" #: ../sdaps/reporttex/__init__.py:168 #, python-format msgid "An occured during creation of the report. Temporary files left in '%s'." msgstr "" sdaps-1.9.8/sdaps/0000755000175000000660000000000013611127124014507 5ustar benjaminlock00000000000000sdaps-1.9.8/sdaps/__init__.py0000644000175000000660000000500713611126743016630 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """ sdaps has a modular design. It ships a core python module called "model" which is responsible for storing and basic modification of the data. When other modules like "recognize" are loaded they '''extend''' the original model. As an example the "recognize" module contains everything required to analyize the scanned data and find checkmarks. However, it will in addition load the "image", "matrix" and "surface" modules. These three modules are responsible for loading and caching the image data and doing some pre-processing of the image data(transformation matrix calculation). Please have a look at the documentation of the "model" package. """ __version__ = '1.9.8' import sys from . import paths from . import script import os import argparse from .utils.ugettext import ugettext, ungettext _ = ugettext def init(local_run=False): paths.init(local_run, __path__[0]) def main(local_run=False): """The main SDAPS interface routine. It initilizes all modules, parses the command line and passes control over to the selected function.""" init(local_run) from . import log log.activate_redirects() from . import cmdline cmdline = script.parser.parse_args() cmdline = vars(cmdline) log.interactive('-'*78 + '\n') log.interactive(('- SDAPS -- %s' % cmdline['_name']) + '\n') log.interactive('-'*78 + '\n') try: return cmdline['_func'](cmdline) except: import traceback string = traceback.format_exc() sys.stderr.write(string) sys.exit(1) # Guess whether documentation is generated, if it is # setup for local run. if 'sphinx' in sys.argv[0]: paths.init(True, os.path.join(sys.path[0], 'sdaps')) sdaps-1.9.8/sdaps/add/0000755000175000000660000000000013611127124015237 5ustar benjaminlock00000000000000sdaps-1.9.8/sdaps/add/__init__.py0000644000175000000660000000737613367301321017366 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import os from sdaps import model from sdaps import image import shutil from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext def _insert_dummy_pages(survey, duplex_scan): # Insert dummy pages if the survey is duplex and the duplex option was not # passed if survey.defs.duplex: # One image per questionnaire page in duplex mode image_count_factor = 1 # No dummy pages in duplex mode insert_dummy_pages = False else: # Two images per questionnaire page in duplex mode image_count_factor = 2 # In simplex mode insertion of dummy pages depends on the command line # optoin (default is True) if duplex_scan: insert_dummy_pages = False else: insert_dummy_pages = True return insert_dummy_pages, image_count_factor def check_image(survey, file, duplex_scan=False, force=False, message=False): insert_dummy_pages, image_count_factor = _insert_dummy_pages(survey, duplex_scan) if not image.check_tiff_monochrome(file): if message: print(_('Invalid input file %s. You need to specify a (multipage) monochrome TIFF as input.') % (file,)) return False num_pages = image.get_tiff_page_count(file) c = survey.questionnaire.page_count if not insert_dummy_pages: c = c * image_count_factor # This test is on the image count that needs to come from the file if num_pages % c != 0 and not force: if message: print(_('Not adding %s because it has a wrong page count (needs to be a mulitple of %i).') % (file, c)) return False return True def add_image(survey, file, duplex_scan=False, force=False, copy=True): insert_dummy_pages, image_count_factor = _insert_dummy_pages(survey, duplex_scan) if not check_image(survey, file, duplex_scan, force, message=True): return num_pages = image.get_tiff_page_count(file) c = survey.questionnaire.page_count if not insert_dummy_pages: c = c * image_count_factor if insert_dummy_pages: c = c * image_count_factor if copy: tiff = survey.new_path('%i.tif') shutil.copyfile(file, tiff) else: tiff = file if copy: tiff = os.path.basename(tiff) else: tiff = os.path.relpath(os.path.abspath(tiff), survey.survey_dir) pages = list(range(num_pages)) while len(pages) > 0: sheet = model.sheet.Sheet() survey.add_sheet(sheet) while len(pages) > 0 and len(sheet.images) < c: img = model.sheet.Image() sheet.add_image(img) img.filename = tiff img.tiff_page = pages.pop(0) # And a dummy page if required if insert_dummy_pages: img = model.sheet.Image() sheet.add_image(img) img.filename = "DUMMY" img.tiff_page = -1 img.ignored = True sdaps-1.9.8/sdaps/annotate/0000755000175000000660000000000013611127124016320 5ustar benjaminlock00000000000000sdaps-1.9.8/sdaps/annotate/__init__.py0000644000175000000660000000375013367301321020437 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2012, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from gi.repository import Poppler import cairo from . import buddies import os.path def annotate(survey, infile=None, outfile=None): if infile is None: infile = 'file://' + os.path.abspath(survey.path('questionnaire.pdf')) else: infile = 'file://' + os.path.abspath(infile) if outfile is None: outfile = survey.path('annotated_questionnaire.pdf') pdf = Poppler.Document.new_from_file(infile, None) width, height = pdf.get_page(0).get_size() output = cairo.PDFSurface(outfile, 2*width, 2*height) cr = cairo.Context(output) for p in range(survey.questionnaire.page_count): pdf.get_page(p).render_for_printing(cr) cr.save() # Use mm space in here. cr.scale(72.0 / 25.4, 72.0 / 25.4) layout_info = dict() layout_info['twidth'] = width / 72.0 * 25.4 - 20 # mm layout_info['xshift'] = width / 72.0 * 25.4 + 10 # mm layout_info['ypos'] = 15 # mm layout_info['font'] = "Sans 3" layout_info['boxfont'] = "Sans 2" # And, render the questions on top (1 based page numbers here) survey.questionnaire.annotate.draw(cr, p + 1, layout_info) cr.restore() cr.show_page() sdaps-1.9.8/sdaps/annotate/buddies.py0000644000175000000660000002174113367603635020334 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, 2013, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # This file duplicates some drawing code from the gui module. from gi.repository import Pango from gi.repository import PangoCairo import cairo import math from sdaps import model from sdaps import defs colorcycle_pos = 0 colorcycle = [(1, 0, 0), (0.5, 0.5, 0), (0, 0.5, 0.5), (0.5, 0, 0.5)] LINE_WIDTH = 25.4/72 MIN_FREETEXT_SIZE = 4.0 def cycle_color(): global colorcycle_pos colorcycle_pos = (colorcycle_pos + 1) % len(colorcycle) def set_rgb_from_color_cycle(cr): global colorcycle_pos, colorcycle cr.set_source_rgba(*(colorcycle[colorcycle_pos] + (0.5,))) def inner_box(cr, x, y, width, height): line_width = cr.get_line_width() cr.rectangle(x + line_width / 2.0, y + line_width / 2.0, width - line_width, height - line_width) def inner_ellipse(cr, x, y, width, height): cr.save() cr.translate(x + width / 2.0, y + height / 2.0) line_width = cr.get_line_width() cr.scale((width - line_width) / 2.0, (height - line_width) / 2.0) cr.arc(0, 0, 1.0, 0, 2*math.pi) # Restore old matrix (without removing the current path) cr.restore() def create_layout(cr, text, layout_info, indent=0): layout = PangoCairo.create_layout(cr) layout.set_text(text, -1) # Dont recreate the description all the time? font = Pango.FontDescription(layout_info['font']) layout.set_font_description(font) layout.set_width((layout_info['twidth'] - 2 * indent) * Pango.SCALE) layout.set_wrap(Pango.WrapMode.WORD_CHAR) layout.indent = indent return layout def show_layout(cr, layout, layout_info, skip=1.25): x, y = layout_info['xshift'] + layout.indent, layout_info['ypos'] + skip cr.move_to(x, y) cr.set_source_rgb(0, 0, 0) PangoCairo.show_layout(cr, layout) layout_info['ypos'] = layout_info['ypos'] + layout.get_pixel_size()[1] + skip # Return the position of the baseline y += layout.get_baseline() / Pango.SCALE return x, y class Questionnaire(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'annotate' obj_class = model.questionnaire.Questionnaire def draw(self, cr, page_number, layout_info): cr.set_source_rgba(0.0, 0.0, 1.0, 0.5) cr.set_line_width(LINE_WIDTH) # Draw corner marks. cr.move_to(defs.corner_mark_left + defs.corner_mark_length, defs.corner_mark_top) cr.line_to(defs.corner_mark_left, defs.corner_mark_top) cr.line_to(defs.corner_mark_left, defs.corner_mark_top+defs.corner_mark_length) cr.move_to(self.obj.survey.defs.paper_width - defs.corner_mark_right - defs.corner_mark_length, defs.corner_mark_top) cr.line_to(self.obj.survey.defs.paper_width - defs.corner_mark_right, defs.corner_mark_top) cr.line_to(self.obj.survey.defs.paper_width - defs.corner_mark_right, defs.corner_mark_top + defs.corner_mark_length) cr.move_to(defs.corner_mark_left + defs.corner_mark_length, self.obj.survey.defs.paper_height - defs.corner_mark_bottom) cr.line_to(defs.corner_mark_left, self.obj.survey.defs.paper_height - defs.corner_mark_top) cr.line_to(defs.corner_mark_left, self.obj.survey.defs.paper_height - defs.corner_mark_top - defs.corner_mark_length) cr.move_to(self.obj.survey.defs.paper_width - defs.corner_mark_right - defs.corner_mark_length, self.obj.survey.defs.paper_height - defs.corner_mark_top) cr.line_to(self.obj.survey.defs.paper_width - defs.corner_mark_right, self.obj.survey.defs.paper_height - defs.corner_mark_top) cr.line_to(self.obj.survey.defs.paper_width - defs.corner_mark_right, self.obj.survey.defs.paper_height - defs.corner_mark_top - defs.corner_mark_length) cr.stroke() for qobject in self.obj.qobjects: cycle_color() qobject.annotate.draw(cr, page_number, layout_info) class QObject(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'annotate' obj_class = model.questionnaire.QObject def draw(self, cr, page_number, layout_info): pass class Head(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'annotate' obj_class = model.questionnaire.Head def draw(self, cr, page_number, layout_info): # There is no page number for head objects. layout = create_layout(cr, self.obj.id_str() + " " + self.obj.title, layout_info) xpos, ypos = show_layout(cr, layout, layout_info) class Question(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'annotate' obj_class = model.questionnaire.Question def draw(self, cr, page_number, layout_info): # Does the sheet contain this question? if page_number == self.obj.page_number: layout = create_layout(cr, self.obj.id_str() + " " + self.obj.question, layout_info, 3) xpos, ypos = show_layout(cr, layout, layout_info, 3) # iterate over boxes for box in self.obj.boxes: box.annotate.draw(cr, layout_info) class Range(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'annotate' obj_class = model.questionnaire.Range def draw(self, cr, page_number, layout_info): # Does the sheet contain this question? if page_number == self.obj.page_number: layout = create_layout(cr, self.obj.id_str() + " " + self.obj.question, layout_info, 3) xpos, ypos = show_layout(cr, layout, layout_info, 3) # Lower range layout = create_layout(cr, self.obj.answers[0], layout_info, 10) xpos, ypos = show_layout(cr, layout, layout_info, 3) cr.move_to(self.obj.boxes[self.obj.range[0]].x, self.obj.boxes[self.obj.range[0]].y) cr.line_to(xpos, ypos) cr.set_line_width(LINE_WIDTH) set_rgb_from_color_cycle(cr) cr.stroke() # Upper range layout = create_layout(cr, self.obj.answers[1], layout_info, 10) xpos, ypos = show_layout(cr, layout, layout_info, 3) cr.move_to(self.obj.boxes[self.obj.range[1]].x, self.obj.boxes[self.obj.range[1]].y) cr.line_to(xpos, ypos) cr.set_line_width(LINE_WIDTH) set_rgb_from_color_cycle(cr) cr.stroke() for i, box in enumerate(self.obj.boxes): hide_if_empty = (self.obj.range[0] <= i <= self.obj.range[1]) box.annotate.draw(cr, layout_info, hide_if_empty=hide_if_empty) class Box(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'annotate' obj_class = model.questionnaire.Checkbox def draw_box(self, cr): inner_box(cr, self.obj.x, self.obj.y, self.obj.width, self.obj.height) cr.stroke() def draw(self, cr, layout_info, hide_if_empty=False): if not hide_if_empty or self.obj.text: layout = create_layout(cr, self.obj.id_str() + " " + self.obj.text, layout_info, 6) xpos, ypos = show_layout(cr, layout, layout_info) cr.move_to(self.obj.x, self.obj.y) cr.line_to(xpos, ypos) cr.set_line_width(LINE_WIDTH) set_rgb_from_color_cycle(cr) cr.stroke() cr.set_fill_rule(cairo.FILL_RULE_EVEN_ODD) cr.set_source_rgba(0.0, 0.0, 1.0, 0.5) cr.set_line_width(LINE_WIDTH) self.draw_box(cr) text = str(self.obj.id[-1]) layout = PangoCairo.create_layout(cr) layout.set_text(text, len(text)) # Dont recreate the description all the time? font = Pango.FontDescription(layout_info['boxfont']) layout.set_font_description(font) cr.move_to(self.obj.x + LINE_WIDTH, self.obj.y + LINE_WIDTH) PangoCairo.show_layout(cr, layout) cr.new_path() class Checkbox(Box, metaclass=model.buddy.Register): name = 'annotate' obj_class = model.questionnaire.Checkbox def draw_box(self, cr): if self.obj.form == "box": inner_box(cr, self.obj.x, self.obj.y, self.obj.width, self.obj.height) cr.stroke() elif self.obj.form == "ellipse": inner_ellipse(cr, self.obj.x, self.obj.y, self.obj.width, self.obj.height) cr.stroke() class Textbox(Box, metaclass=model.buddy.Register): name = 'annotate' obj_class = model.questionnaire.Textbox sdaps-1.9.8/sdaps/boxgallery/0000755000175000000660000000000013611127124016657 5ustar benjaminlock00000000000000sdaps-1.9.8/sdaps/boxgallery/__init__.py0000644000175000000660000000714713367301321021002 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import cairo from gi.repository import Pango from gi.repository import PangoCairo from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext import copy from . import buddies def paint_box(cr, mm_to_pt, x, y, box, key): cr.save() cr.set_matrix(mm_to_pt) cr.translate(x, y) cr.scale(25.4 / 300.0, 25.4 / 300.0) cr.set_source_rgb(0, 0, 0) cr.mask_surface(box[2][0], 0, 0) if box[3] and key in box[3] and box[3][key] is not None: cr.set_source_surface(box[3][key][0], box[3][key][1] - box[2][1], box[3][key][2] - box[2][2]) cr.paint() cr.restore() cr.save() tmp_x, tmp_y = mm_to_pt.transform_point(x, y) tmp_width, tmp_height = mm_to_pt.transform_distance(8, 13) tmp_x, tmp_y = mm_to_pt.transform_point(x, y + 8.0) # Print bold if detected ON value = box[1][key] if key in box[1] else -1 if box[0]: t = "%.2f" % value else: t = "%.2f" % value cr.move_to(tmp_x, tmp_y) layout = PangoCairo.create_layout(cr) layout.set_markup(t, -1) font = Pango.FontDescription("serif 6") layout.set_font_description(font) PangoCairo.show_layout(cr, layout) cr.restore() def fill_page(cr, mm_to_pt, checkboxes, key): y = 15 y_step = 13 x_step = 10 x_max = 210 - 15 - 8 y_max = 297 - 15 - 8 while y < y_max: x = 15 while x < x_max: if len(checkboxes) == 0: return box = checkboxes.pop(0) paint_box(cr, mm_to_pt, x, y, box, key) x += x_step y += y_step def boxgallery(survey, debugrecognition): # Enable debug image creation in the C module if debugrecognition: from sdaps import image image.enable_debug_surface_creation(True) survey.questionnaire.boxgallery.init(debugrecognition) survey.iterate_progressbar(survey.questionnaire.boxgallery.get_checkbox_images) checkboxes = survey.questionnaire.boxgallery.checkboxes survey.questionnaire.boxgallery.clean() keys = set() for checkbox in checkboxes: keys = keys.union(iter(checkbox[1].keys())) for key in keys: print(_("Rendering boxgallery for metric \"%s\"." % key)) draw_list = copy.copy(checkboxes) draw_list.sort(key=lambda x: x[1][key] if key in x[1] else 0) # Hardcode 300dpi # Hardcode the mm size: # 3.5 + 0.4mm = 3.9mm mm_to_pt = cairo.Matrix(72.0 / 25.4, 0, 0, 72.0 / 25.4, 0, 0) page = 1 pdf = cairo.PDFSurface(survey.path('boxgallery-%s.pdf' % key), 595, 842) cr = cairo.Context(pdf) while len(draw_list) > 0: fill_page(cr, mm_to_pt, draw_list, key) cr.show_page() pdf.flush() page += 1 del pdf del cr sdaps-1.9.8/sdaps/boxgallery/buddies.py0000644000175000000660000000763613367301321020665 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import cairo from sdaps import model from sdaps import surface from sdaps import matrix class Sheet(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'boxgallery' obj_class = model.sheet.Sheet def load(self): for image in self.obj.images: if not image.ignored: image.surface.load() def clean(self): for image in self.obj.images: if not image.ignored: image.surface.clean() class Questionnaire(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'boxgallery' obj_class = model.questionnaire.Questionnaire def init(self, debugrecognition): self.checkboxes = list() self.debugrecognition = debugrecognition def clean(self): del self.checkboxes def get_checkbox_images(self): if self.obj.survey.sheet.valid: self.obj.survey.sheet.boxgallery.load() for qobject in self.obj.qobjects: self.checkboxes.extend(qobject.boxgallery.get_checkbox_images(self.debugrecognition)) self.obj.survey.sheet.boxgallery.clean() class QObject(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'boxgallery' obj_class = model.questionnaire.QObject def get_checkbox_images(self, debugrecognition): return [] class Question(QObject, metaclass=model.buddy.Register): name = 'boxgallery' obj_class = model.questionnaire.Question def get_checkbox_images(self, debugrecognition): boxes = [] for box in self.obj.boxes: new_box = box.boxgallery.get_checkbox_image(debugrecognition) if new_box: boxes.append(new_box) return boxes class Box(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'boxgallery' obj_class = model.questionnaire.Box def get_checkbox_image(self, debugrecognition): return None class Checkbox(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'boxgallery' obj_class = model.questionnaire.Checkbox def get_checkbox_image(self, debugrecognition): image = self.obj.sheet.get_page_image(self.obj.page_number) border = 1.5 mm_to_px = image.matrix.mm_to_px() px_x, px_y = mm_to_px.transform_point( self.obj.data.x - border, self.obj.data.y - border) px_x, px_y = int(px_x), int(px_y) px_width, px_height = mm_to_px.transform_distance( self.obj.data.width + 2 * border, self.obj.data.height + 2 * border) dest = cairo.ImageSurface( cairo.FORMAT_A1, int(px_width), int(px_height)) src = image.surface.surface cr = cairo.Context(dest) cr.set_source_surface(src, -px_x, -px_y) cr.set_operator(cairo.OPERATOR_SOURCE) cr.paint() del cr dest.flush() debug = {} if debugrecognition: # Run the recognition for this checkbox self.obj.recognize.recognize() debug = self.obj.recognize.debug return (self.obj.data.state, self.obj.data.metrics, (dest, px_x, px_y), debug) sdaps-1.9.8/sdaps/calculate.py0000644000175000000660000001704713367301321017030 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """This module contains buddy objects to calculate statistics from the data. It is possible to search for large changes between different filters by calling the "reference" function after a calculation. After this the significant boolean will be set for new calculations (with different filters) if there is a large deviation from the old value.""" import math from sdaps import model class Questionnaire(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'calculate' obj_class = model.questionnaire.Questionnaire def init(self): """Initialize or reset the state of the calculate module.""" self.count = 0 # iterate over qobjects for qobject in self.obj.qobjects: qobject.calculate.init() def read(self): """The function collects the data from a sheet. You should use :py:meth:`Survey.iterate` to call it for each sheet that needs to be counted.""" self.count += 1 # iterate over qobjects for qobject in self.obj.qobjects: qobject.calculate.read() def calculate(self): """Call once after :py:meth:`Questionnaire.calculate.read` to calculate statistical values like the standard deviation.""" # iterate over qobjects for qobject in self.obj.qobjects: qobject.calculate.calculate() def reference(self): """Can be used to calculate a reference value. You can later check whether there was a significant difference to the previous run. The `significant` property will be set accordingly.""" # iterate over qobjects for qobject in self.obj.qobjects: qobject.calculate.reference() class QObject(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'calculate' obj_class = model.questionnaire.QObject def init(self): pass def read(self): pass def calculate(self): pass def reference(self): pass class Question(QObject, metaclass=model.buddy.Register): name = 'calculate' obj_class = model.questionnaire.Question class Choice(Question, metaclass=model.buddy.Register): """ :ivar count: Number of times the question was answered. :ivar values: Dictionary for each box with the ratio the answer was choosen. :ivar significant: Whether there was a significant difference to the reference run. """ name = 'calculate' obj_class = model.questionnaire.Choice def init(self): self.count = 0 self.values = {box.value: 0 for box in self.obj.boxes} self.significant = {box.value: 0 for box in self.obj.boxes} def read(self): self.count += 1 for item in self.obj.get_answer(): self.values[item] += 1 def calculate(self): if self.count: for value in self.values: self.values[value] = self.values[value] / float(self.count) if hasattr(self, 'ref_count'): self.significant[value] = ( abs(self.values[value] - self.ref_values[value]) > 0.1) def reference(self): self.ref_count = self.count self.ref_values = self.values class Option(Choice, metaclass=model.buddy.Register): name = 'calculate' obj_class = model.questionnaire.Option def read(self): answer = self.obj.get_answer() if answer is not False and answer >= 0: self.count += 1 self.values[answer] += 1 class Range(Option, metaclass=model.buddy.Register): """ :ivar count: Number of times the question was answered. :ivar values: Dictionary for each box with the ratio the value was choosen. :ivar mean: The average value that was choosen. :ivar standard_deviation: The average value that was choosen. :ivar significant: Whether there was a significant difference to the reference run. """ name = 'calculate' obj_class = model.questionnaire.Range def init(self): Option.init(self) self.significant = 0 self.mean = 0 self.standard_deviation = 0 self.range_count = 0 self.range_values = {} for box in self.obj.boxes[self.obj.range[0]:self.obj.range[1] + 1]: self.range_values[box.value] = 0 self.range_min = min(self.range_values) self.range_max = max(self.range_values) def calculate(self): self.mean = 0 self.range_count = 0 if self.count: for key in self.range_values: self.range_count += self.values[key] self.range_values[key] = self.values[key] del self.values[key] for key in self.values: self.values[key] = self.values[key] / float(self.count) if self.range_count > 0: # First calculate the mean for key in self.range_values: self.mean += key * self.range_values[key] self.mean = self.mean / float(self.range_count) # Now we can calculate the standard deviation for key in self.range_values: self.standard_deviation += self.range_values[key] * pow(key - self.mean, 2) self.standard_deviation = math.sqrt(self.standard_deviation / float(self.range_count)) # And finally store the percentage rather than count for each answer for key in self.range_values: self.range_values[key] = self.range_values[key] / float(self.count) if hasattr(self, 'ref_count'): self.significant = abs(self.mean - self.ref_mean) > 0.1 def reference(self): self.ref_count = self.count self.ref_mean = self.mean class Additional_FilterHistogram(Question, metaclass=model.buddy.Register): name = 'calculate' obj_class = model.questionnaire.Additional_FilterHistogram def init(self): self.count = 0 self.values = [0] * len(self.obj.answers) self.significant = [0] * len(self.obj.answers) def read(self): self.count += 1 for i in range(len(self.obj.answers)): filter = clifilter.clifilter( self.obj.questionnaire.survey, self.obj.filters[i]) if filter(): self.values[i] += 1 def calculate(self): if self.count: self.significant = dict() for i in range(len(self.values)): self.values[i] = self.values[i] / float(self.count) if hasattr(self, 'ref_count'): self.significant[i] = ( abs(self.values[i] - self.ref_values[i]) > 0.1) def reference(self): self.ref_count = self.count self.ref_values = self.values sdaps-1.9.8/sdaps/clifilter.py0000644000175000000660000000357513367301321017051 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """ This modules contains a helper function to allow writing filter expressions on the command line of sdaps. Using this it is for example possible to create a report that only contains a subset of all filled out sheets. """ class Locals(object): def __init__(self, survey): self.survey = survey self.qobjects = dict([ (qobject.id_filter(), qobject) for qobject in self.survey.questionnaire.qobjects ]) def __getitem__(self, key): if key in self.qobjects: return self.qobjects[key].get_answer() elif key in ['survey_id', 'questionnaire_id', 'global_id', 'valid', 'quality', 'recognized', 'verified', 'complete']: return getattr(self.survey.sheet, key) else: raise KeyError def clifilter(survey, expression): if expression is None or expression.strip() == '': return lambda: True exp = compile(expression, '', 'eval') globals = __builtins__ locals = Locals(survey) return lambda: eval(exp, globals, locals) sdaps-1.9.8/sdaps/cmdline/0000755000175000000660000000000013611127124016122 5ustar benjaminlock00000000000000sdaps-1.9.8/sdaps/cmdline/__init__.py0000644000175000000660000000056313367301321020240 0ustar benjaminlock00000000000000 # Simply import all submodules from . import add from . import annotate from . import boxgallery from . import convert from . import cover from . import csvdata from . import gui from . import ids from . import info from . import recognize from . import reorder from . import report from . import reporttex from . import reset from . import setup from . import stamp sdaps-1.9.8/sdaps/cmdline/add.py0000644000175000000660000001121313405476471017237 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import os import tempfile from sdaps import model from sdaps import script from sdaps import log from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext parser = script.add_project_subparser("add", help=_("Add scanned questionnaires to the survey."), description=_("""This command is used to add scanned images to the survey. The image data needs to be a (multipage) 300dpi monochrome TIFF file. You may choose not to copy the data into the project directory. In that case the data will be referenced using a relative path.""")) parser.add_argument('--convert', help=_("Convert given files and add the result."), dest="convert", action="store_true", default=False) parser.add_argument('--3d-transform', help=_("""Do a 3D-transformation after finding the corner marks. If the corner marks are not found then the image will be added as-is."""), dest="transform", action="store_true", default=False) parser.add_argument('--force', help=_("Force adding the images even if the page count is wrong (only use if you know what you are doing)."), action="store_true", default=False) parser.add_argument('--copy', help=_("Copy the files into the directory (default)."), dest="copy", action="store_true", default=True) parser.add_argument('--no-copy', help=_("Do not copy the files into the directory."), dest="copy", action="store_false") parser.add_argument('--duplex', help=_("Images contain a duplex scan of a simplex questionnaire (default: simplex scan)."), dest="duplex", action="store_true", default=False) parser.add_argument('images', help=_("A number of TIFF image files."), nargs='+') @script.connect(parser) @script.logfile def add(cmdline): import sys from sdaps.add import add_image, check_image from sdaps import image error = False survey = model.survey.Survey.load(cmdline['project']) filelist = [] deletelist = [] if not cmdline['convert']: for file in cmdline['images']: filelist.append(file) if not check_image(survey, file, cmdline['duplex'], cmdline['force'], message=True): error=True if error: return else: if not cmdline['copy']: log.error(_("The --no-copy option is not compatible with --convert!")) return 1 try: from sdaps.convert import convert_images except: log.error("Need to convert the images to monochrome TIFF, however the conversion module cannot be imported. You are likely missing the OpenCV dependency.") return 1 print(_("Converting input files into a single temporary file.")) tmp = tempfile.mktemp(suffix='.tif', prefix='sdaps-convert-') deletelist.append(tmp) filelist.append(tmp) # Run conversion # TODO: Allow 3D transformation here! try: convert_images(cmdline['images'], tmp, survey.defs.paper_width, survey.defs.paper_height, cmdline['transform']) if not check_image(survey, tmp, cmdline['duplex'], cmdline['force']): log.error(_("The page count of the created temporary file does not work with this survey.")) raise AssertionError() except Exception as e: log.error(str(e)) log.error(_("Running the conversion failed.")) error = True raise if not error: for file in filelist: print(_('Processing %s') % file) add_image(survey, file, cmdline['duplex'], cmdline['force'], cmdline['copy']) print(_('Done')) for file in deletelist: try: os.unlink(file) except OSError: pass if error: return 1 else: survey.save() return 0 sdaps-1.9.8/sdaps/cmdline/annotate.py0000644000175000000660000000262613405476471020330 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2012, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import os from sdaps import model from sdaps import script from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext parser = script.add_project_subparser("annotate", help=_("Annotate the questionnaire and show the recognized positions."), description=_("""This command is mainly a debug utility. It creates an annotated version of the questionnaire, with the information that SDAPS knows about it overlayed on top.""")) @script.connect(parser) @script.logfile def annotate(cmdline): from sdaps.annotate import annotate survey = model.survey.Survey.load(cmdline['project']) return annotate(survey) sdaps-1.9.8/sdaps/cmdline/boxgallery.py0000644000175000000660000000413713405476471020666 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """ This modules contains a script for the user to output all boxes sorted by their coverage. This can be used to adjust magic values for checkbox recognition. """ from sdaps import model from sdaps import script from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext parser = script.add_project_subparser("boxgallery", help=_("Create PDFs with boxes sorted by the detection heuristics."), description=_("""SDAPS uses multiple heuristics to detect determine the state of checkboxes. There is a list for each heuristic giving the expected state and the quality of the value (see defs.py). Using this command a PDF will be created for each of the heuristics so that one can adjust the values.""")) parser.add_argument('--debugrecognition', action="store_true", help=_('Reruns part of the recognition process and retrieves debug images from this step.'), default=False) @script.connect(parser) @script.logfile def boxgallery(cmdline): # We need to load the buddies before the survey is loaded. if cmdline['debugrecognition']: from sdaps.recognize import buddies survey = model.survey.Survey.load(cmdline['project']) from sdaps import boxgallery return boxgallery.boxgallery(survey, cmdline['debugrecognition']) sdaps-1.9.8/sdaps/cmdline/convert.py0000644000175000000660000000447413405476471020202 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2013, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import os import sys from sdaps import model from sdaps import script from sdaps import log from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext parser = script.add_project_subparser("convert", help=_("Convert a set of images to the correct image format."), description=_("""This command can be used if you scanned files in something other than the expected monochrome TIFF mode. All given files will be loaded, converted to monochrome and stored in a multipage 1bpp TIFF file. Optionally, you can select \"3D transformation"\ ,which may facilitate working with photos of questionnaires instead of scans.""")) parser.add_argument('--3d-transform', help=_("""Do a 3D-transformation after finding the corner marks. If they are not found, the image will be processed as-is."""), dest="transform", action="store_true", default=False) parser.add_argument('-o', '--output', required=True, help=_("The location of the output file."), dest="output") parser.add_argument('images', help=_("A number of TIFF image files."), nargs='+') @script.connect(parser) @script.logfile def convert(cmdline): from sdaps.convert import convert_images if cmdline['output'] is None: log.error(_("No output filename specified!")) sys.exit(1) # We need a survey only for the paper size! survey = model.survey.Survey.load(cmdline['project']) convert_images(cmdline['images'], cmdline['output'], survey.defs.paper_width, survey.defs.paper_height, cmdline['transform']) sdaps-1.9.8/sdaps/cmdline/cover.py0000644000175000000660000000275413405476471017637 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from sdaps import model from sdaps import script from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext parser = script.add_project_subparser("cover", help=_("Create a cover for the questionnaires."), description=_("""This command creates a cover page for questionnaires. All the metadata of the survey will be printed on the page.""")) parser.add_argument('-o', '--output', help=_("Filename to store the data to (default: cover_%%i.pdf)")) @script.connect(parser) @script.logfile def cover(cmdline): from sdaps import cover survey = model.survey.Survey.load(cmdline['project']) cover.cover(survey, cmdline['output']) sdaps-1.9.8/sdaps/cmdline/csvdata.py0000644000175000000660000001060413473752775020150 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """ This module implements a simple export/import to/from CSV files. """ import os import sys from sdaps import model from sdaps import script from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext parser = script.add_subparser("csv", help=_("Import or export data to/from CSV files."), description=_("""Import or export data to/from a CSV file. The first line is a header which defines questionnaire_id and global_id, and a column for each checkbox and textfield. Note that the import is currently very limited, as you need to specifiy the questionnaire ID to select the sheet which should be updated.""")) # Set required as an attribute rather than kwarg so that it works with python <3.7 subparser = parser.add_subparsers(dest='subcommand') subparser.required = True export = subparser.add_parser('export', help=_("Export data to CSV file.")) script.add_project_argument(export) export.add_argument('-o', '--output', help=_("Filename to store the data to (default: data_%%i.csv)")) export.add_argument('-d', '--delimiter', help=_("The delimiter used in the CSV file (default ',')"), default=',', action='store') export.add_argument('-f', '--filter', help=_("Filter to only export a partial dataset.")) export.add_argument('--images', help=_("Export images of freeform fields."), dest='export_images', action='store_const', const=True, default=False) export.add_argument('--question-images', help=_("Export an image for each question that includes all boxes."), dest='export_question_images', action='store_const', const=True, default=False) export.add_argument('--quality', help=_("Export the recognition quality for each checkbox."), dest='export_quality', action='store_const', const=True, default=False) export.set_defaults(direction='export') import_ = subparser.add_parser('import', help=_("Import data to from a CSV file.")) script.add_project_argument(import_) import_.add_argument('file', help=_("The file to import.")) import_.set_defaults(direction='import') @script.connect(parser) @script.logfile def csvdata(cmdline): from sdaps import csvdata from sdaps.utils.image import ImageWriter survey = model.survey.Survey.load(cmdline['project']) if cmdline['direction'] == 'export': if cmdline['output']: if cmdline['output'] == '-': outfd = os.dup(sys.stdout.fileno()) outfile = os.fdopen(outfd, 'w') else: filename = cmdline['output'] outfile = open(filename, 'w') else: filename = survey.new_path('data_%i.csv') outfile = open(filename, 'w') csvoptions = { 'delimiter' : cmdline['delimiter'] } if cmdline['export_images'] or cmdline['export_question_images'] and cmdline['output'] != '-': img_path = os.path.dirname(filename) img_prefix = os.path.join(os.path.splitext(os.path.basename(filename))[0], 'img') image_writer = ImageWriter(img_path, img_prefix) else: image_writer = None return csvdata.csvdata_export(survey, outfile, image_writer, filter=cmdline['filter'], export_images=cmdline['export_images'], export_question_images=cmdline['export_question_images'], export_quality=cmdline['export_quality'], csvoptions=csvoptions) elif cmdline['direction'] == 'import': return csvdata.csvdata_import(survey, open(cmdline['file'], 'r')) else: raise AssertionError sdaps-1.9.8/sdaps/cmdline/gui.py0000644000175000000660000000300713405476471017275 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from sdaps import model from sdaps import script from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext parser = script.add_project_subparser("gui", help=_("Launch a GUI. You can view and alter the (recognized) answers with it."), description=_("""This command launches a graphical user interface that can be used to correct answers. You need to run "recognize" before using it. """)) parser.add_argument('-f', '--filter', help=_("Filter to only show a partial dataset.")) @script.connect(parser) @script.logfile def gui(cmdline): from sdaps import gui survey = model.survey.Survey.load(cmdline['project']) return gui.gui(survey, cmdline) sdaps-1.9.8/sdaps/cmdline/ids.py0000644000175000000660000000527113405476471017275 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from sdaps import model from sdaps import script import os import sys from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext parser = script.add_project_subparser("ids", help=_("Export and import questionnaire IDs."), description=_("""This command can be used to import and export questionnaire IDs. It only makes sense in projects where such an ID is printed on the questionnaire. Note that you can also add IDs by using the stamp command, which will give you the PDF at the same time.""")) parser.add_argument('-o', '--output', help=_("Filename to store the data to (default: ids_%%i)")) parser.add_argument('-a', '--add', metavar="FILE", help=_("Add IDs to the internal list from the specified file.")) @script.connect(parser) @script.logfile def ids(cmdline): survey = model.survey.Survey.load(cmdline['project']) if cmdline['add']: if cmdline['add'] == '-': ids = sys.stdin else: ids = open(cmdline['add'], 'r') to_add = [] for line in ids.readlines(): # Skip empty lines if line == "": continue line = line line = line.strip('\r\n') to_add.append(survey.validate_questionnaire_id(line)) survey.questionnaire_ids += to_add survey.save() else: if cmdline['output']: if cmdline['output'] == '-': outfd = os.dup(sys.stdout.fileno()) ids = os.fdopen(outfd, 'w') else: filename = cmdline['output'] ids = open(filename, 'w') else: filename = survey.new_path('ids_%i') ids = open(filename, 'w') for id in survey.questionnaire_ids: ids.write(str(id)) ids.write('\n') if ids != sys.stdout: ids.close() sdaps-1.9.8/sdaps/cmdline/info.py0000644000175000000660000000457213405476471017454 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from sdaps import model from sdaps import script from sdaps import log from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext parser = script.add_project_subparser("info", help=_("Display and modify metadata of project."), description=_("""This command lets you modify the metadata of the SDAPS project. You can modify, add and remove arbitrary keys that will be printed on the report. The only key that always exist is "title". If no key is given then a list of defined keys is printed.""")) parser.add_argument('-d', '--delete', action="store_true", help=_("Delete the key and value pair.")) parser.add_argument('key', nargs="?", help=_("The key to display or modify.")) parser.add_argument('value', nargs="?", help=_("Set the given key to this value.")) @script.connect(parser) @script.logfile def info(cmdline): survey = model.survey.Survey.load(cmdline['project']) if cmdline['key']: key = cmdline['key'].strip() if cmdline['value']: value = cmdline['value'].strip() if key == "title": survey.title = value else: survey.info[key] = value elif cmdline['delete']: del survey.info[key] else: if key == "title": print(survey.title) else: print(survey.info[key]) else: log.interactive(_('Existing fields:\n')) print("title") for key in list(survey.info.keys()): print(key) survey.save() sdaps-1.9.8/sdaps/cmdline/recognize.py0000644000175000000660000000404613405476471020502 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from sdaps import model from sdaps import script from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext parser = script.add_project_subparser("recognize", help=_("Run the optical mark recognition."), description=_("""Iterates over all images and runs the optical mark recognition. It will reevaluate sheets even if "recognize" has already run or manual changes were made.""")) parser.add_argument('--identify', help=_("Only identify the page properties, but don't recognize the checkbox states."), action="store_true", default=False) parser.add_argument('--rerun', '-r', help=_("Rerun the recognition for all pages. The default is to skip all pages that were recognized or verified already."), action="store_true", default=False) @script.connect(parser) @script.logfile def recognize(cmdline): survey = model.survey.Survey.load(cmdline['project']) from sdaps import recognize if not cmdline['rerun']: filter = lambda : not (survey.sheet.verified or survey.sheet.recognized) else: filter = lambda: True if cmdline['identify']: return recognize.identify(survey, filter) else: return recognize.recognize(survey, filter) sdaps-1.9.8/sdaps/cmdline/reorder.py0000644000175000000660000000276513405476471020165 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2012, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from sdaps import model from sdaps import script from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext parser = script.add_project_subparser("reorder", help=_("Reorder pages according to questionnaire ID."), description=_("""This command reorders all pages according to the already recognized questionnaire ID. To use it add all the files to the project, then run a partial recognition using "recognize --identify". After this you have to run this command to reorder the data for the real recognition. """)) @script.connect(parser) @script.logfile def reorder(cmdline): survey = model.survey.Survey.load(cmdline['project']) from sdaps import reorder return reorder.reorder(survey) sdaps-1.9.8/sdaps/cmdline/report.py0000644000175000000660000000555013405476471020031 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from sdaps import model from sdaps import script from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext parser = script.add_project_subparser("report", help=_("Create a PDF report."), description=_("""This command creates a PDF report using reportlab that contains statistics and if selected the freeform fields.""")) parser.add_argument('-f', '--filter', help=_("Filter to only export a partial dataset.")) parser.add_argument('--all-filters', help=_("Create a filtered report for every checkbox."), action="store_true") parser.add_argument('-s', '--short', help=_("Short format (without freeform text fields)."), action="store_const", const="short", dest="format") parser.add_argument('-l', '--long', help=_("Detailed output. (default)"), dest="format", action="store_const", const="long", default="long") parser.add_argument('--suppress-images', help=_('Do not include original images in the report. This is useful if there are privacy concerns.'), dest='suppress', action='store_const', const='images') parser.add_argument('--suppress-substitutions', help=_('Do not use substitutions instead of images.'), dest='suppress', action='store_const', const='substitutions', default=None) parser.add_argument('-p', '--paper', help=_('The paper size used for the output (default: locale dependent)'), dest='papersize') parser.add_argument('-o', '--output', help=_("Filename to store the data to (default: report_%%i.pdf)")) @script.connect(parser) @script.logfile def report(cmdline): from sdaps import report survey = model.survey.Survey.load(cmdline['project']) if cmdline['format'] == 'short': small = 1 else: small = 0 if cmdline['all_filters']: return report.stats(survey, cmdline['filter'], cmdline['output'], cmdline['papersize'], small, cmdline['suppress']) else: return report.report(survey, cmdline['filter'], cmdline['output'], cmdline['papersize'], small, cmdline['suppress']) sdaps-1.9.8/sdaps/cmdline/reporttex.py0000644000175000000660000000461213405476471020550 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, 2011, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from sdaps import model from sdaps import script from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext parser = script.add_project_subparser("report_tex", help=_("Create a PDF report using LaTeX."), description=_("""This command creates a PDF report using LaTeX that contains statistics and freeform fields.""")) parser.add_argument('--suppress-images', help=_('Do not include original images in the report. This is useful if there are privacy concerns.'), dest='suppress', action='store_const', const='images') parser.add_argument('--suppress-substitutions', help=_('Do not use substitutions instead of images.'), dest='suppress', action='store_const', const='substitutions', default=None) parser.add_argument('--create-tex', help=_('Save the generated TeX files instead of the final PDF.'), dest='create-tex', action='store_true', default=False) parser.add_argument('-p', '--paper', help=_('The paper size used for the output (default: locale dependent)'), dest='papersize') parser.add_argument('-o', '--output', help=_("Filename to store the data to (default: report_%%i.pdf)")) parser.add_argument('-f', '--filter', help=_("Filter to only export a partial dataset.")) @script.connect(parser) @script.logfile def report_tex(cmdline): from sdaps import reporttex survey = model.survey.Survey.load(cmdline['project']) return reporttex.report(survey, cmdline['filter'], cmdline['output'], cmdline['papersize'], suppress=cmdline['suppress'], tex_only=cmdline['create-tex']) sdaps-1.9.8/sdaps/cmdline/reset.py0000644000175000000660000000246113405476471017636 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2012, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from sdaps import model from sdaps import script from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext parser = script.add_project_subparser("reset", help=_("Reset project into original state"), description=_("""This command does a full reset of the project. All data will be discarded and only the empty project is left. """)) @script.connect(parser) @script.logfile def reset(cmdline): survey = model.survey.Survey.load(cmdline['project']) from sdaps import reset return reset.reset(survey) sdaps-1.9.8/sdaps/cmdline/setup.py0000644000175000000660000000415213423053443017641 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2010, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from sdaps import model from sdaps import script from sdaps import defs from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext parser = script.add_project_subparser("setup", help=_("Create a new survey using a LaTeX document."), description=_("""Create a new survey from a LaTeX document. You need to be using the SDAPS class. All the metadata and options for the project can be set inside the LaTeX document.""")) parser.add_argument('questionnaire.tex', help=_("The LaTeX Document")) parser.add_argument('-a', '--add', help=_("Additional files that are required by the LaTeX document and need to be copied into the project directory."), action='append', default=[]) parser.add_argument('-e', '--engine', help=_("The engine to use to compile LaTeX documents."), default=defs.latex_engine) parser.add_argument('additional_questions', nargs='?', help=_("Additional questions that are not part of the questionnaire.")) @script.connect(parser) def setup(cmdline): from sdaps import setuptex return setuptex.setup(cmdline['project'], cmdline['questionnaire.tex'], cmdline['engine'], cmdline['additional_questions'], cmdline['add']) sdaps-1.9.8/sdaps/cmdline/stamp.py0000644000175000000660000000411513405476471017636 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from sdaps import model from sdaps import script from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext parser = script.add_project_subparser("stamp", help=_("Add marks for automatic processing."), description=_("""This command creates the printable document. Depending on the projects setting you are required to specifiy a source for questionnaire IDs.""")) parser.add_argument('-r', '--random', metavar="N", help=_("If using questionnaire IDs, create N questionnaires with randomized IDs."), type=int) parser.add_argument('-f', '--file', help=_("If using questionnaire IDs, create questionnaires from the IDs read from the specified file.")) parser.add_argument('--existing', action="store_true", help=_("If using questionnaire IDs, create questionnaires for all stored IDs.")) parser.add_argument('-o', '--output', help=_("Filename to store the data to (default: stamp_%%i.pdf)")) @script.connect(parser) @script.logfile def stamp(cmdline): from sdaps import stamp survey = model.survey.Survey.load(cmdline['project']) if cmdline['output'] is None: output = survey.new_path('stamped_%i.pdf') else: output = cmdline['output'] return stamp.stamp(survey, output, cmdline) sdaps-1.9.8/sdaps/convert/0000755000175000000660000000000013611127124016167 5ustar benjaminlock00000000000000sdaps-1.9.8/sdaps/convert/__init__.py0000644000175000000660000000312213346275473020316 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2013, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from sdaps import image from sdaps.utils import opencv from sdaps import log from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext def convert_images(images, outfile, paper_width, paper_height, transform=False): portrait = paper_height >= paper_width for i, (img, filename, page) in enumerate(opencv.iter_images_and_pages(images)): img = opencv.ensure_orientation(img, portrait) img = opencv.sharpen(img) if transform: try: img = opencv.transform_using_corners(img, paper_width, paper_height) except AssertionError: log.warn(_("Could not apply 3D-transformation to image '%s', page %i!") % (filename, page)) mono = opencv.convert_to_monochrome(img) image.write_a1_to_tiff(outfile, opencv.to_a1_surf(mono)) sdaps-1.9.8/sdaps/cover/0000755000175000000660000000000013611127124015625 5ustar benjaminlock00000000000000sdaps-1.9.8/sdaps/cover/__init__.py0000644000175000000660000000272513367301321017745 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from sdaps import template from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext def cover(survey, output=None): story = template.story_title(survey) subject = [] for key, value in survey.info.items(): subject.append('%(key)s: %(value)s' % {'key': key, 'value': value}) subject = '\n'.join(subject) if output: filename = output else: filename = survey.new_path('cover_%i.pdf') doc = template.DocTemplate( filename, _('SDAPS questionnaire'), { 'title': survey.title, 'subject': subject } ) doc.build(story) sdaps-1.9.8/sdaps/csvdata/0000755000175000000660000000000013611127124016134 5ustar benjaminlock00000000000000sdaps-1.9.8/sdaps/csvdata/__init__.py0000644000175000000660000000317213346275473020270 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import csv from sdaps import clifilter from sdaps import model from . import buddies def csvdata_export(survey, csvfile, image_writer, filter=None, export_images=False, export_question_images=False, export_quality=False, csvoptions={}): # compile clifilter filter = clifilter.clifilter(survey, filter) # export survey.questionnaire.csvdata.open_csv(csvfile, image_writer, export_images, export_question_images, export_quality, csvoptions) survey.iterate( survey.questionnaire.csvdata.export_data, filter, ) survey.questionnaire.csvdata.export_finish() def csvdata_import(survey, csvfile): csvreader = csv.DictReader(csvfile) for data in csvreader: survey.questionnaire.csvdata.import_data(data) csvfile.close() survey.save() sdaps-1.9.8/sdaps/csvdata/buddies.py0000644000175000000660000002253113450213350020126 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import csv from sdaps import model import os import os.path from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext class Questionnaire(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'csvdata' obj_class = model.questionnaire.Questionnaire def open_csv(self, csvfile, image_writer=None, export_images=False, export_question_images=False, export_quality=False, csv_options={}): header = ['questionnaire_id', 'global_id', 'empty', 'valid', 'recognized', 'review', 'verified'] self.export_quality = export_quality self.image_writer = image_writer if image_writer is not None and (export_images or export_question_images): from sdaps.utils.image import ImageWriter self.export_images = export_images self.export_question_images = export_question_images else: self.export_images = None self.export_question_images = None for qobject in self.obj.qobjects: header.extend(qobject.csvdata.export_header()) self.file = csvfile self.csv = csv.DictWriter(self.file, header, **csv_options) self.csv.writerow({value: value for value in header}) def export_data(self): data = { 'questionnaire_id': str(self.obj.sheet.questionnaire_id), 'global_id': str(self.obj.sheet.global_id), 'empty' : str(int(self.obj.sheet.empty)), 'valid' : str(int(self.obj.sheet.valid)), 'recognized' : str(int(self.obj.sheet.recognized)), 'review' : str(self.obj.sheet.review_comment if self.obj.sheet.review_comment else ''), 'verified' : str(int(self.obj.sheet.verified)), } for qobject in self.obj.qobjects: data.update(qobject.csvdata.export_data()) self.csv.writerow(data) def export_finish(self): self.file.flush() del self.file del self.csv def import_data(self, data): try: self.obj.survey.goto_questionnaire_id(data['questionnaire_id']) except ValueError: print((_('Not importing unknown questionnaire ID "%s"') % data['questionnaire_id'])) # The sheet does not exist # Ignore it pass else: if 'valid' in data: self.obj.sheet.valid = bool(int(data['valid'])) if 'review' in data: self.obj.sheet.review_comment = data['review'] if 'verified' in data: for img in self.obj.sheet.images: img.verified = bool(int(data['verified'])) for qobject in self.obj.qobjects: qobject.csvdata.import_data(data) class QObject(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'csvdata' obj_class = model.questionnaire.QObject def export_header(self): header = [ self.obj.id_csv() + '_review' ] if self.obj.questionnaire.csvdata.export_question_images and self.obj.boxes: header += [self.obj.id_csv() + '_image'] return header def export_data(self): data = {} if self.obj.questionnaire.csvdata.export_question_images: if self.obj.boxes: img = self.obj.questionnaire.csvdata.image_writer.output_boxes(self.obj.boxes, real=False) data[self.obj.id_csv() + '_image'] = img data[self.obj.id_csv() + '_review'] = str(self.obj.data.review_comment if self.obj.data.review_comment else '') return data def import_data(self, data): if self.obj.id_csv() + '_review' in data: self.obj.data.review_comment = data[self.obj.id_csv() + '_review'] class Choice(QObject, metaclass=model.buddy.Register): name = 'csvdata' obj_class = model.questionnaire.Choice def export_header(self): header = QObject.export_header(self) for box in self.obj.boxes: header += box.csvdata.export_header() return header def export_data(self): data = QObject.export_data(self) for box in self.obj.boxes: data.update(box.csvdata.export_data()) return data def import_data(self, data): QObject.import_data(self, data) for box in self.obj.boxes: box.csvdata.import_data(data) class Text(QObject, metaclass=model.buddy.Register): name = 'csvdata' obj_class = model.questionnaire.Text def export_header(self): header = QObject.export_header(self) for box in self.obj.boxes: header += box.csvdata.export_header() return header def export_data(self): data = QObject.export_data(self) for box in self.obj.boxes: data.update(box.csvdata.export_data()) return data def import_data(self, data): QObject.import_data(self, data) for box in self.obj.boxes: box.csvdata.import_data(data) class Option(QObject, metaclass=model.buddy.Register): name = 'csvdata' obj_class = model.questionnaire.Option def export_header(self): header = QObject.export_header(self) header += [self.obj.id_csv()] return header def export_data(self): data = {self.obj.id_csv(): '%i' % self.obj.get_answer()} data.update(QObject.export_data(self)) return data def import_data(self, data): QObject.import_data(self, data) if self.obj.id_csv() in data: self.obj.set_answer(int(data[self.obj.id_csv()])) class Additional_Mark(QObject, metaclass=model.buddy.Register): name = 'csvdata' obj_class = model.questionnaire.Additional_Mark def export_header(self): return QObject.export_header(self) + [self.obj.id_csv()] def export_data(self): data = {self.obj.id_csv(): '%i' % self.obj.get_answer()} data.update(QObject.export_data(self)) return data def import_data(self, data): QObject.import_data(self, data) if self.obj.id_csv() in data: self.obj.set_answer(int(data[self.obj.id_csv()])) class Box(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'csvdata' obj_class = model.questionnaire.Box def export_header(self): header = [self.obj.id_csv()] if self.obj.question.questionnaire.csvdata.export_quality: header += [self.obj.id_csv() + '_quality'] return header def export_data(self): data = {self.obj.id_csv() : str(int(self.obj.data.state))} if self.obj.question.questionnaire.csvdata.export_quality: data.update({self.obj.id_csv() + '_quality' : self.obj.data.quality}) return data def import_data(self, data): if not self.obj.id_csv() in data: return self.obj.data.state = int(data[self.obj.id_csv()]) class Textbox(Box, metaclass=model.buddy.Register): name = 'csvdata' obj_class = model.questionnaire.Textbox def export_header(self): header = [self.obj.id_csv()] return header def export_data(self): data = str(int(self.obj.data.state)) image_writer = self.obj.question.questionnaire.csvdata.image_writer if self.obj.data.state and self.obj.data.text: data = self.obj.data.text elif self.obj.data.state and self.obj.question.questionnaire.csvdata.export_images: data = image_writer.output_box(self.obj) data = { self.obj.id_csv() : data } return data def import_data(self, data): if not self.obj.id_csv() in data: return try: state = int(data[self.obj.id_csv()]) text = '' except ValueError: state = 1 text = str(data[self.obj.id_csv()]) self.obj.data.state = state self.obj.data.text = text class Codebox(Textbox, metaclass=model.buddy.Register): name = 'csvdata' obj_class = model.questionnaire.Codebox def export_header(self): header = [self.obj.id_csv()] return header def export_data(self): data = str(int(self.obj.data.state)) if self.obj.data.state and self.obj.data.text: data = self.obj.data.text data = { self.obj.id_csv() : data } return data def import_data(self, data): if not self.obj.id_csv() in data: return try: state = int(data[self.obj.id_csv()]) text = '' except ValueError: state = 1 text = str(data[self.obj.id_csv()]) self.obj.data.state = state self.obj.data.text = text sdaps-1.9.8/sdaps/defs.py0000644000175000000660000001657513370123277016027 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """ Defs ==== This module contains constants and some magic values. """ # Corner Marks ============================================ # The position of the corner markings from the side of the paper corner_mark_left = 10.0 # mm corner_mark_right = 10.0 # mm corner_mark_top = 12.0 # mm corner_mark_bottom = 12.0 # mm corner_mark_length = 20.0 # mm # Bottom page margin (for QR-Code size calculation in fallback rendering) bottom_page_margin = 25.0 # mm # Length in mm of the corner marks in the scanned image corner_mark_min_length = 15 # mm corner_mark_max_length = 22 # mm # The distance into the image that will be searched for the corner mark. # Basically a square area of this size will be searched in each corner. corner_mark_search_distance = 50 # mm # Corner Boxes ============================================ # What corners are filled for each page, this is choosen so that # the page number and rotation can be derived from the information. # Order: top left, top right, bottom left, bottom right corner_boxes = [ [0, 1, 1, 1], [1, 1, 0, 0], [1, 0, 1, 1], [1, 0, 1, 0], [1, 0, 0, 0], [0, 0, 0, 1], ] # Size of the corner boxes(measured from the center of the line) corner_box_width = 3.5 # mm corner_box_height = 3.5 # mm # Distance from the corner marker(and also the distance to the codebox) corner_box_padding = 3 # mm # The coverage above which a cornerbox is considered to be a logical 1 cornerbox_on_coverage = 0.6 # Codebox ================================================= # Length in bits codebox_length = 16 # bits codebox_step = 3.5 # mm codebox_width = codebox_step * codebox_length # mm codebox_height = 3.5 # mm # Padding that is ignored when testing the image whether it is 1/0 codebox_offset = 0.75 # mm # The font and size of the font for the text that is printed between the codeboxes codebox_text_font = 'Courier-Bold' codebox_text_font_size = 10.5 # pt # This is added to the vertical position to shift the text visually into the center codebox_text_baseline_shift = 3 # mm # Magic values for recognition # The coverage above which a codebox is considered to be a logical 1 codebox_on_coverage = 0.7 # Code 128 Barcodes ======================================= code128_barwidth = 0.33 # mm. This is 0.93pt or 3.89px after scanning code128_height = 6.5 # pt(5 mm) code128_hpad = 6.5 # mm code128_vpad = 4.02 # mm code128_text_font = 'Courier' code128_text_font_size = 9 # pt # Checkbox ================================================ checkbox_metrics = {} # The metrics is a mapping from the value to the quality and expected # checkbox state. # It works by searching the interval that we are in, and doing # a linear interpolation. # At state changes the point should be inserted twice. # The touple is(metric, state, quality). To disable one you can just # insert two dummy points with zero quality. To try and find better # values have a look at the output of "boxgallery". Any suggestions # for improvements(also algorithmic wise) are always welcome! checkbox_metrics['checkcorrect'] = {} checkbox_metrics['checkcorrect']['coverage'] = \ [(0, 0, 1.0), (0.02, 0, 0.9), (0.05, 0, 0.3), (0.05, 1, 0.3), (0.1, 1, 1.0), (0.4, 1, 1.0), (0.5, 1, 0.2), (0.5, 0, 0.2), (0.7, 0, 0.3), (1.0, 0, 0.6)] checkbox_metrics['checkcorrect']['cov-lines-removed'] = \ [(0, 1, 0), (0.01, 1, 0), (0.07, 1, 1.0), (0.10, 1, 1.0), (0.13, 1, 0.3), (0.13, 0, 0.3), (0.25, 0, 0.7), (1, 0, 0.7)] checkbox_metrics['checkcorrect']['cov-min-size'] = \ [(0, 0, .9), (0.35, 0, 0.0), (0.35, 1, 0.0), (0.5, 1, 0.9), (0.55, 1, 1.0), (0.8, 1, 1.0), (0.9, 1, 0.9), (0.95, 1, 0.5), (0.95, 0, 0.5), (0.99, 0, 0.9), (1.0, 0, 1.0)] # Same as above, but no correction mode. A light check is enough. checkbox_metrics['check'] = {} checkbox_metrics['check']['coverage'] = \ [(0, 0, 1.0), (0.02, 0, 0.9), (0.05, 0, 0.3), (0.05, 1, 0.3), (0.1, 1, 1.0), (1.0, 0, 1.0)] checkbox_metrics['check']['cov-lines-removed'] = \ [(0, 1, 0), (1, 1, 0)] checkbox_metrics['check']['cov-min-size'] = \ [(0, 1, 0), (1, 1, 0)] # Similar, but a light checkmark, or just dirt will be ignored. checkbox_metrics['fill'] = {} checkbox_metrics['fill']['coverage'] = \ [(0, 0, 1.0), (0.2, 0, 0.9), (0.3, 0, 0), (0.3, 1, 0), (0.4, 1, 1.0), (1.0, 1, 1.0)] checkbox_metrics['fill']['cov-lines-removed'] = \ [(0, 1, 0), (1, 1, 0)] checkbox_metrics['fill']['cov-min-size'] = \ [(0, 1, 0), (1, 1, 0)] # Textbox ================================================= # Tolerance for the text box corner adjustment. If the difference is more than # this in mm, the adjusted values will be discarded. find_box_corners_tolerance = 1.5 # mm # The size in mm of the area that is scanned during checking of textboxes. The step # is the x/y distance in mm of each checked area. They overlap on purpose. textbox_scan_step_x = 1.0 # mm textbox_scan_step_y = 1.0 # mm textbox_scan_width = 2.0 # mm textbox_scan_height = 2.0 # mm # The pixel coverage of the scan area that is required for it to # be considered writing. textbox_scan_coverage = 0.06 # Minimum size in mm for a textbox to be considered filled in. # This is usefull because otherwise small dirt dots will be considered writing. textbox_minimum_writing_width = 5 # mm textbox_minimum_writing_height = 5 # mm # Distance to stay away from the outline in mm so that it will not be detected # as handwriting. The "uncorrected" value is used when the corners have not been # detected correctly, which should hopefully never happen. textbox_scan_padding = 0.5 # mm textbox_scan_uncorrected_padding = 1.5 # mm # Padding tha will always be added to the textbox size if content has been recognized. # This is important because we want the outline to be visible if someone wrote # over the outline(so that the reader can see that the software worked correctly). textbox_extra_padding = 0.5 # mm # Image =================================================== # The width of the lines in the scanned image. # All lines are 1pt wide(1/72 inch or 25.4/72 mm) image_line_width = 24.4/72. # mm # The coverage that the line needs to have for recognition image_line_coverage = 0.35 # Allowed characters in code 128 barcodes (only ascii for now) c128_chars = [chr(i) for i in range(32, 127)] #+ [u'È', u'É', u'Ê', u'Ë', u'Ì', u'Í', u'Î', u'Ï', u'Ð', u'Ñ', u'Ò', u'Ó'] # External commands ======================================= #: The binary used to compile latex documents. latex_engine = "pdflatex" #: A function that is called after fork and before exec of the latex engine. #: This is useful when e.g. the LateX environment should be secured. latex_preexec_hook = None sdaps-1.9.8/sdaps/gui/0000755000175000000660000000000013611127124015273 5ustar benjaminlock00000000000000sdaps-1.9.8/sdaps/gui/__init__.py0000644000175000000660000004122213575707425017426 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2007-2008, Christoph Simon # Copyright(C) 2007-2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """ This modules contains a GTK+ user interface. With the help of this GUI it is possible to manually correct the automatic recognition and do basic debugging. """ import gi gi.require_version('Gtk', '3.0') from gi.repository import GObject from gi.repository import GLib from gi.repository import Gtk from gi.repository import Gdk import os import time import sys import signal from sdaps import model from sdaps import surface from sdaps import recognize from sdaps import clifilter from sdaps import defs from sdaps import paths from sdaps import log from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext from .sheet_widget import SheetWidget from . import buddies from . import widget_buddies zoom_steps = [0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.25, 1.5, 2.0, 2.5, 3.0] def gui(survey, cmdline): filter = clifilter.clifilter(survey, cmdline['filter']) provider = Provider(survey, filter) if not provider.images: log.error(_("The survey does not have any images! Please add images (and run recognize) before using the GUI.")) return 1 try: # Exit the mainloop if Ctrl+C is pressed in the terminal. GLib.unix_signal_add_full(GLib.PRIORITY_HIGH, signal.SIGINT, lambda *args : Gtk.main_quit(), None) except AttributeError: # Whatever, it is only to enable Ctrl+C anyways pass MainWindow(provider).run() class Provider(object): def __init__(self, survey, filter, by_quality=False): self._by_quality = by_quality self.survey = survey self.images = list() self.qualities = list() self.survey.iterate(self, filter) self.qualities.sort(reverse=False) self.index = 0 # There may be no images. This error is # caught and printed in the "gui" function. if not self.images: return self.image.surface.load_rgb() self.survey.goto_sheet(self.image.sheet) #self._surface = None def __call__(self): # Add all images that are "valid" ie. everything except back side of # a simplex printout. new_images = [img for img in self.survey.sheet.images if not img.ignored] # Try to sort the images, which may fail if the page numbers have not been # recognised try: new_images.sort(key=lambda Image: Image.page_number) except TypeError: pass self.images.extend(new_images) # Insert each image of the sheet into the qualities array for i in range(len(new_images)): self.qualities.append((self.survey.sheet.quality, len(self.qualities))) def next(self, cycle=True): if self.index >= len(self.images) - 1: if cycle: new_index = 0 else: return False else: new_index = self.index + 1 self.image.surface.clean() self.index = new_index self.image.surface.load_rgb() self.survey.goto_sheet(self.image.sheet) return True def previous(self, cycle=True): if self.index <= 0: if cycle: new_index = len(self.images) - 1 else: return False else: new_index = self.index - 1 self.image.surface.clean() self.index = new_index self.image.surface.load_rgb() self.survey.goto_sheet(self.image.sheet) return True def goto(self, index): if index >= 0 and index < len(self.images): self.image.surface.clean() self.index = index self.image.surface.load_rgb() self.survey.goto_sheet(self.image.sheet) def set_sort_by_quality(self, value): self.image.surface.clean() self._by_quality = value self.image.surface.load_rgb() self.survey.goto_sheet(self.image.sheet) def get_image(self): if self._by_quality: return self.images[self.qualities[self.index][1]] else: return self.images[self.index] image = property(get_image) class MainWindow(object): def __init__(self, provider): self.about_dialog = None self.close_dialog = None self.ask_open_dialog = None self.provider = provider self._load_image = 0 self._builder = Gtk.Builder() if paths.local_run: self._builder.add_from_file( os.path.join(os.path.dirname(__file__), 'main_window.ui')) else: self._builder.add_from_file( os.path.join( paths.prefix, 'share', 'sdaps', 'ui', 'main_window.ui')) self._window = self._builder.get_object("main_window") self._builder.connect_signals(self) self._window.maximize() scrolled_window = self._builder.get_object("sheet_scrolled_window") self.sheet = SheetWidget(self.provider) self.sheet.show() scrolled_window.add(self.sheet) self.data_viewport = self._builder.get_object("data_view") widgets = provider.survey.questionnaire.widget.create_widget() widgets.show_all() self.data_viewport.add(widgets) provider.survey.questionnaire.widget.connect_ensure_visible(self.data_view_ensure_visible) self.sheet.connect('key-press-event', self.sheet_view_key_press) combo = self._builder.get_object("page_number_combo") cell = Gtk.CellRendererText() combo.pack_start(cell, True) combo.add_attribute(cell, 'text', 0) store = Gtk.ListStore(GObject.TYPE_STRING, GObject.TYPE_INT) store.append(row=(_("Page|Invalid"), -1)) for i in range(self.provider.survey.questionnaire.page_count): store.append(row=( ungettext("Page %i", "Page %i", i + 1) % (i + 1), i + 1)) combo.set_model(store) self.sheet.props.zoom = 0.2 # So the buttons are insensitive self.update_ui() def zoom_in(self, *args): cur_zoom = self.sheet.props.zoom try: i = zoom_steps.index(cur_zoom) i += 1 if i < len(zoom_steps): self.sheet.props.zoom = zoom_steps[i] except: self.sheet.props.zoom = 1.0 def zoom_out(self, *args): cur_zoom = self.sheet.props.zoom try: i = zoom_steps.index(cur_zoom) i -= 1 if i >= 0: self.sheet.props.zoom = zoom_steps[i] except: self.sheet.props.zoom = 1.0 def null_event_handler(self, *args): return True def show_about_dialog(self, *args): if not self.about_dialog: self.about_dialog = Gtk.AboutDialog() self.about_dialog.set_program_name("SDAPS") #self.about_dialog.set_version("") self.about_dialog.set_authors( ["Benjamin Berg ", "Ferdinand Schwenk ", "Christoph Simon ", "Tobias Simon "]) self.about_dialog.set_copyright(_("Copyright © 2007-2014 The SDAPS Authors")) self.about_dialog.set_license_type(Gtk.License.GPL_3_0) self.about_dialog.set_comments(_("Scripts for data acquisition with paper based surveys")) self.about_dialog.set_website(_("http://sdaps.org")) self.about_dialog.set_translator_credits(_("translator-credits")) self.about_dialog.set_default_response(Gtk.ResponseType.CANCEL) self.about_dialog.set_transient_for(self._window) self.about_dialog.run() self.about_dialog.hide() return True def update_page_status(self): combo = self._builder.get_object("page_number_combo") turned_toggle = self._builder.get_object("turned_toggle") # Update the combobox if self.provider.image.survey_id == self.provider.survey.survey_id: page_number = self.provider.image.page_number else: page_number = -1 # Find the page_number in the model model = combo.get_model() iter = model.get_iter_first() while iter: i = combo.get_model().get(iter, 1)[0] if page_number == i: combo.set_active_iter(iter) iter = None else: iter = model.iter_next(iter) # Update the toggle turned_toggle.set_active(self.provider.image.rotated or False) def update_ui(self): # Update the next/prev button states #next_button = self._builder.get_object("forward_toolbutton") #prev_button = self._builder.get_object("backward_toolbutton") #next_button.set_sensitive(True) #prev_button.set_sensitive(True) position_label = self._builder.get_object("position_label") quality_label = self._builder.get_object("quality_label") page_spin = self._builder.get_object("page_spin") position_label.set_text(_(" of %i") % len(self.provider.images)) quality_label.set_text(_("Recognition Quality: %.2f") % self.provider.image.sheet.quality) #position_label.props.sensitive = True page_spin.set_range(1, len(self.provider.images)) page_spin.set_value(self.provider.index + 1) self.update_page_status() self.sheet.update_state() self.provider.survey.questionnaire.widget.sync_state(self.provider.image) def go_to_previous_page(self, *args): if not self.provider.previous(cycle=False): dialog = Gtk.MessageDialog( flags=Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT, type=Gtk.MessageType.INFO, buttons=Gtk.ButtonsType.CANCEL, message_format=_("You have reached the first page of the survey. Would you like to go to the last page?")) dialog.set_transient_for(self._window) dialog.add_button(_("Go to last page"), Gtk.ResponseType.OK) if dialog.run() == Gtk.ResponseType.OK: self.provider.previous(cycle=True) dialog.destroy() self.update_ui() return True def go_to_page(self, page): if page == self.provider.index: return True self.provider.goto(int(page)) self.update_ui() return True def go_to_next_page(self, *args): if not self.provider.next(cycle=False): dialog = Gtk.MessageDialog( flags=Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT, type=Gtk.MessageType.INFO, buttons=Gtk.ButtonsType.CANCEL, message_format=_("You have reached the last page of the survey. Would you like to go to the first page?")) dialog.set_transient_for(self._window) dialog.add_button(_("Go to first page"), Gtk.ResponseType.OK) if dialog.run() == Gtk.ResponseType.OK: self.provider.next(cycle=True) dialog.destroy() self.update_ui() return True def page_spin_value_changed_cb(self, *args): page_spin = self._builder.get_object("page_spin") page = page_spin.get_value() - 1 self.go_to_page(page) def page_number_combo_changed_cb(self, *args): combo = self._builder.get_object("page_number_combo") active = combo.get_active_iter() page_number = combo.get_model().get(active, 1)[0] if self.provider.image.page_number != page_number: if page_number != -1: self.provider.image.page_number = page_number self.provider.image.survey_id = self.provider.survey.survey_id else: self.provider.image.page_number = None self.provider.image.survey_id = None self.update_ui() return False def turned_toggle_toggled_cb(self, *args): toggle = self._builder.get_object("turned_toggle") rotated = toggle.get_active() if self.provider.image.rotated != rotated: self.provider.image.rotated = rotated self.provider.image.surface.load_rgb() self.update_ui() return False def quality_sort_toggle_toggled_cb(self, *args): toggle = self._builder.get_object("quality_sort_toggle") self.provider.set_sort_by_quality(toggle.get_active()) self.update_ui() return False def toggle_fullscreen(self, *args): flags = self._window.get_window().get_state() if flags & Gdk.WindowState.FULLSCREEN: self._window.unfullscreen() else: self._window.fullscreen() return True def run_recognition(self, *args): self.provider.survey.questionnaire.recognize.recognize(skip_identify=True, image=self.provider.image) # We need to re-load the page as it gets cleared self.provider.image.surface.load_rgb() return True def save_project(self, *args): self.provider.survey.save() return True def data_view_ensure_visible(self, widget): allocation = widget.get_allocation() vadj = self.data_viewport.props.vadjustment lower = vadj.props.lower upper = vadj.props.upper value = vadj.props.value page_size = vadj.props.page_size value = max(value, allocation.y + allocation.height - page_size) value = min(value, allocation.y) value = max(value, lower) value = min(value, upper) vadj.props.value = value def sheet_view_key_press(self, window, event): # Go to the next when Enter or Tab is pressed enter_keyvals = [Gdk.keyval_from_name(k) for k in ["Return", "KP_Enter", "ISO_Enter"]] if event.keyval in enter_keyvals: # If "Return" is pressed, then the examiner figured that the data # is good. # Mark as verified self.provider.image.verified = True # Mark the sheet as valid if it is verified if self.provider.image.sheet.verified: self.provider.image.sheet.valid = True if event.state & Gdk.ModifierType.SHIFT_MASK: self.go_to_previous_page() else: self.go_to_next_page() return True elif event.keyval == Gdk.KEY_Tab or event.keyval == Gdk.KEY_KP_Tab or event.keyval == Gdk.KEY_ISO_Left_Tab: # Allow tabbing out with Ctrl if event.state & Gdk.ModifierType.CONTROL_MASK: return False if event.state & Gdk.ModifierType.SHIFT_MASK: self.go_to_previous_page() else: self.go_to_next_page() return True return False def quit_application(self, *args): if not self.close_dialog: self.close_dialog = Gtk.MessageDialog( parent=self._window, flags=Gtk.DialogFlags.MODAL, type=Gtk.MessageType.WARNING) self.close_dialog.add_buttons( _("Close without saving"), Gtk.ResponseType.CLOSE, Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE, Gtk.ResponseType.OK) self.close_dialog.set_markup( _("Save the project before closing?\n\nIf you do not save you may lose data.")) self.close_dialog.set_default_response(Gtk.ResponseType.CANCEL) response = self.close_dialog.run() self.close_dialog.hide() if response == Gtk.ResponseType.CLOSE: Gtk.main_quit() return False elif response == Gtk.ResponseType.OK: self.save_project() Gtk.main_quit() return False else: return True def run(self): self._window.show() Gtk.main() sdaps-1.9.8/sdaps/gui/buddies.py0000644000175000000660000003434513575707425017316 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import cairo import math from sdaps import model from sdaps import defs from sdaps import image from sdaps.image import TOP_LEFT, TOP_RIGHT, BOTTOM_RIGHT, BOTTOM_LEFT LINE_WIDTH = 25.4/72 MIN_FREETEXT_SIZE = 4.0 _LEFT = 1 _RIGHT = 2 _TOP = 3 _BOTTOM = 4 def inner_box(cr, x, y, width, height): line_width = cr.get_line_width() cr.rectangle(x + line_width / 2.0, y + line_width / 2.0, width - line_width, height - line_width) def ellipse(cr, x, y, width, height): cr.save() cr.translate(x + width / 2.0, y + height / 2.0) line_width = cr.get_line_width() cr.scale(width / 2.0, height / 2.0) cr.arc(0, 0, 1.0, 0, 2*math.pi) cr.close_path() # Restore old matrix (without removing the current path) cr.restore() def inner_ellipse(cr, x, y, width, height): cr.save() cr.translate(x + width / 2.0, y + height / 2.0) line_width = cr.get_line_width() cr.scale((width - line_width) / 2.0, (height - line_width) / 2.0) cr.arc(0, 0, 1.0, 0, 2*math.pi) cr.close_path() # Restore old matrix (without removing the current path) cr.restore() def centered_circle(cr, x, y, radius): inner_ellipse(cr, x - radius, y - radius, 2*radius, 2*radius) class Questionnaire(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'gui' obj_class = model.questionnaire.Questionnaire def __init__(self, *args): self._fixed_points = [TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT] super().__init__(*args) def draw(self, cr, _image): cr.save() # Draw an outline for the content area cr.set_source_rgba(1.0, 0.0, 0.0, 0.6) cr.set_line_width(LINE_WIDTH) cr.rectangle(defs.corner_mark_left, defs.corner_mark_top, self.obj.survey.defs.paper_width - defs.corner_mark_left - defs.corner_mark_right, self.obj.survey.defs.paper_height - defs.corner_mark_top - defs.corner_mark_bottom) cr.stroke() # Draw draggable corner circles cr.set_source_rgba(0.0, 0.0, 1.0, 0.6) centered_circle(cr, defs.corner_mark_left, defs.corner_mark_top, 5*LINE_WIDTH) if TOP_LEFT in self._fixed_points: cr.fill() else: cr.stroke() centered_circle(cr, self.obj.survey.defs.paper_width - defs.corner_mark_right, defs.corner_mark_top, 5*LINE_WIDTH) if TOP_RIGHT in self._fixed_points: cr.fill() else: cr.stroke() centered_circle(cr, defs.corner_mark_left, self.obj.survey.defs.paper_height - defs.corner_mark_bottom, 5*LINE_WIDTH) if BOTTOM_LEFT in self._fixed_points: cr.fill() else: cr.stroke() centered_circle(cr, self.obj.survey.defs.paper_width - defs.corner_mark_right, self.obj.survey.defs.paper_height - defs.corner_mark_bottom, 5*LINE_WIDTH) if BOTTOM_RIGHT in self._fixed_points: cr.fill() else: cr.stroke() cr.restore() for qobject in self.obj.qobjects: qobject.gui.draw(cr, _image.page_number) def find_box(self, _image, x, y): for qobject in self.obj.qobjects: result = qobject.gui.find_box(_image.page_number, x, y) if result: return result return None def find_edge(self, _image, x, y, tollerance_x, tollerance_y): # Not technically edges, but first try to find the corner circles corner = -1 if math.sqrt((x - defs.corner_mark_left) ** 2 + (y - defs.corner_mark_top) ** 2) < 5 * LINE_WIDTH + tollerance_x: corner = TOP_LEFT if math.sqrt((x + defs.corner_mark_right - self.obj.survey.defs.paper_width) ** 2 + (y - defs.corner_mark_top) ** 2) < 5 * LINE_WIDTH + tollerance_x: corner = TOP_RIGHT if math.sqrt((x - defs.corner_mark_left) ** 2 + (y + defs.corner_mark_bottom - self.obj.survey.defs.paper_height) ** 2) < 5 * LINE_WIDTH + tollerance_x: corner = BOTTOM_LEFT if math.sqrt((x + defs.corner_mark_right - self.obj.survey.defs.paper_width) ** 2 + (y + defs.corner_mark_bottom - self.obj.survey.defs.paper_height) ** 2) < 5 * LINE_WIDTH + tollerance_x: corner = BOTTOM_RIGHT if corner > -1: try: self._fixed_points.remove(corner) except: pass self._fixed_points = [corner] + self._fixed_points[:2] return (self.obj, (_image, corner)) for qobject in self.obj.qobjects: result = qobject.gui.find_edge(_image.page_number, x, y, tollerance_x, tollerance_y) if result: return result return None def move_edge(self, args, x, y): # Corner was moved, we need to update the matrix in a way to fit the # moved point and the other three "fixed" points # This is largely copy of the calculation in image.c calculate_matrix() _image, corner = args corners = [None, None, None, None] if TOP_LEFT in self._fixed_points: corners[TOP_LEFT] = (defs.corner_mark_left, defs.corner_mark_top) if TOP_RIGHT in self._fixed_points: corners[TOP_RIGHT] = (self.obj.survey.defs.paper_width - defs.corner_mark_right, defs.corner_mark_top) if BOTTOM_LEFT in self._fixed_points: corners[BOTTOM_LEFT] = (defs.corner_mark_left, self.obj.survey.defs.paper_height - defs.corner_mark_bottom) if BOTTOM_RIGHT in self._fixed_points: corners[BOTTOM_RIGHT] = (self.obj.survey.defs.paper_width - defs.corner_mark_right, self.obj.survey.defs.paper_height - defs.corner_mark_bottom) # Put in the location of the corner that is being adjusted corners[corner] = (x, y) # Transform each corner into pixel space m = _image.matrix.mm_to_px() corners = [m.transform_point(*c) if c is not None else None for c in corners] # Useful constants mm_x = defs.corner_mark_left mm_width = self.obj.sheet.survey.defs.paper_width - defs.corner_mark_left - defs.corner_mark_right mm_y = defs.corner_mark_top mm_height = self.obj.sheet.survey.defs.paper_height - defs.corner_mark_top - defs.corner_mark_bottom m = image.matrix_from_corners_2d(corners, mm_x, mm_y, mm_width, mm_height) _image.matrix.set_px_to_mm(m) class QObject(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'gui' obj_class = model.questionnaire.QObject def draw(self, cr, page_number): pass def find_box(self, page_number, x, y): pass def find_edge(self, page_number, x, y, tollerance_x, tollerance_y): return None class Question(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'gui' obj_class = model.questionnaire.Question def draw(self, cr, page_number): # Does the sheet contain this question? if page_number == self.obj.page_number: # iterate over boxes for box in self.obj.boxes: box.gui.draw(cr) def find_box(self, page_number, x, y): # Does the sheet contain this question? if page_number == self.obj.page_number: # iterate over boxes for box in self.obj.boxes: result = box.gui.find(x, y) if result is not None: return result return None def find_edge(self, page_number, x, y, tollerance_x, tollerance_y): # Does the sheet contain this question? if page_number == self.obj.page_number: # iterate over boxes for box in self.obj.boxes: result = box.gui.find_edge(x, y, tollerance_x, tollerance_y) if result is not None: return result return None class Box(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'gui' obj_class = model.questionnaire.Checkbox def draw(self, cr): cr.set_fill_rule(cairo.FILL_RULE_EVEN_ODD) cr.set_source_rgba(0.57, 1.0, 0.0, 0.5) cr.set_line_width(self.obj.lw) inner_box(cr, self.obj.data.x, self.obj.data.y, self.obj.data.width, self.obj.data.height) cr.stroke() def find(self, x, y): if self.obj.data.x < x < self.obj.data.x + self.obj.data.width: if self.obj.data.y < y < self.obj.data.y + self.obj.data.height: return self.obj return None def find_edge(self, x, y, tollerance_x, tollerance_y): return None class Checkbox(Box, metaclass=model.buddy.Register): name = 'gui' obj_class = model.questionnaire.Checkbox def find(self, x, y): if self.obj.data.x - 2*LINE_WIDTH < x < self.obj.data.x + self.obj.data.width + 2*LINE_WIDTH: if self.obj.data.y - 2*LINE_WIDTH < y < self.obj.data.y + self.obj.data.height + 2*LINE_WIDTH: return self.obj return None def draw(self, cr): cr.save() cr.set_fill_rule(cairo.FILL_RULE_EVEN_ODD) if self.obj.data.quality < 0.5: cr.save() cr.set_line_width(2*LINE_WIDTH) cr.set_source_rgba(1.0, 0.0, 0.2, 0.6) if self.obj.form == "box": inner_box(cr, self.obj.data.x - 4*LINE_WIDTH, self.obj.data.y - 4*LINE_WIDTH, self.obj.data.width+8*LINE_WIDTH, self.obj.data.height+8*LINE_WIDTH) cr.stroke() elif self.obj.form == "ellipse": inner_ellipse(cr, self.obj.data.x - 4*LINE_WIDTH, self.obj.data.y - 4*LINE_WIDTH, self.obj.data.width+8*LINE_WIDTH, self.obj.data.height+8*LINE_WIDTH) cr.stroke() cr.restore() cr.set_source_rgba(0.57, 1.0, 0.0, 0.5) cr.set_line_width(self.obj.lw) if self.obj.data.state: if self.obj.form == "box": cr.rectangle(self.obj.data.x - 2*LINE_WIDTH, self.obj.data.y - 2*LINE_WIDTH, self.obj.data.width + 4*LINE_WIDTH, self.obj.data.height + 4*LINE_WIDTH) cr.fill() elif self.obj.form == "ellipse": ellipse(cr, self.obj.data.x - 2*LINE_WIDTH, self.obj.data.y - 2*LINE_WIDTH, self.obj.data.width + 4*LINE_WIDTH, self.obj.data.height + 4*LINE_WIDTH) cr.fill() else: if self.obj.form == "box": inner_box(cr, self.obj.data.x, self.obj.data.y, self.obj.data.width, self.obj.data.height) cr.stroke() elif self.obj.form == "ellipse": inner_ellipse(cr, self.obj.data.x, self.obj.data.y, self.obj.data.width, self.obj.data.height) cr.stroke() cr.restore() class Textbox(Box, metaclass=model.buddy.Register): name = 'gui' obj_class = model.questionnaire.Textbox def draw(self, cr): cr.save() cr.set_fill_rule(cairo.FILL_RULE_EVEN_ODD) cr.set_source_rgba(0.57, 1.0, 0.0, 0.5) if self.obj.data.state: cr.set_line_width(2 * LINE_WIDTH + self.obj.lw) else: cr.set_line_width(self.obj.lw) inner_box(cr, self.obj.data.x, self.obj.data.y, self.obj.data.width, self.obj.data.height) cr.stroke() cr.restore() def find_edge(self, x, y, tollerance_x, tollerance_y): if self.obj.data.x - tollerance_x <= x and \ self.obj.data.x + tollerance_x >= x and \ self.obj.data.y <= y and \ self.obj.data.y + self.obj.data.height >= y: return(self.obj, _LEFT) if self.obj.data.x + self.obj.data.width - tollerance_x <= x and \ self.obj.data.x + self.obj.data.width + tollerance_x >= x and \ self.obj.data.y <= y and \ self.obj.data.y + self.obj.data.height >= y: return(self.obj, _RIGHT) if self.obj.data.y - tollerance_y <= y and \ self.obj.data.y + tollerance_y >= y and \ self.obj.data.x <= x and \ self.obj.data.x + self.obj.data.width >= x: return(self.obj, _TOP) if self.obj.data.y + self.obj.data.height - tollerance_y <= y and \ self.obj.data.y + self.obj.data.height + tollerance_y >= y and \ self.obj.data.x <= x and \ self.obj.data.x + self.obj.data.width >= x: return(self.obj, _BOTTOM) def move_edge(self, side, x, y): if side == _LEFT: x = max(x, defs.corner_mark_left) new_width = max(MIN_FREETEXT_SIZE, self.obj.data.width + self.obj.data.x - x) x = self.obj.data.x + (self.obj.data.width - new_width) self.obj.data.width = new_width self.obj.data.x = x elif side == _RIGHT: x = min(x, self.obj.question.questionnaire.survey.defs.paper_width - defs.corner_mark_right) new_width = max(MIN_FREETEXT_SIZE, x - self.obj.data.x) new_width = min(new_width, self.obj.data.x + self.obj.data.width) self.obj.data.width = new_width elif side == _TOP: y = max(y, defs.corner_mark_top) new_height = max(MIN_FREETEXT_SIZE, self.obj.data.height + self.obj.data.y - y) new_y = self.obj.data.y + (self.obj.data.height - new_height) self.obj.data.height = new_height self.obj.data.y = new_y elif side == _BOTTOM: y = min(y, self.obj.question.questionnaire.survey.defs.paper_height - defs.corner_mark_bottom) new_height = max(MIN_FREETEXT_SIZE, y - self.obj.data.y) self.obj.data.height = new_height sdaps-1.9.8/sdaps/gui/main_window.ui0000644000175000000660000005335213575707425020176 0ustar benjaminlock00000000000000 100 1 10 navigation navigation_accel_group Forward gtk-go-forward Previous gtk-go-back Zoom In gtk-zoom-in Zoom Out gtk-zoom-out False SDAPS True False vertical True False False True False _File True True False gtk-open False False True True gtk-save False True False True True False True False gtk-quit False True False True True False True False _View True True False True action-next-page True False True action-prev-page True False True False True False _Help True True False gtk-about False True False True True False True 0 True False zoom-in True False True False True zoom-out True False True False True False True False False True action-prev-page True False True False True action-next-page True False True False True False True False False True False True False True gtk-fullscreen False True False True False True Recognize Page False True False True False False True False True False True True adjustment1 False False False True False True False False False False True False False True False True False True False False False False True False True Page Rotated True False True False True False False True False True False True Sort by Quality True False True False True False True False label False True False True 1 True True True True GDK_STRUCTURE_MASK | GDK_SMOOTH_SCROLL_MASK in True True True True True False 5 natural natural none True True True True 2 sdaps-1.9.8/sdaps/gui/sheet_widget.py0000644000175000000660000003724613575707425020355 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2007-2008, Christoph Simon # Copyright(C) 2007-2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import math from gi.repository import GObject from gi.repository import Gtk from gi.repository import Gdk import cairo import copy import os from sdaps import defs from sdaps import model from sdaps import matrix class SheetWidget(Gtk.DrawingArea, Gtk.Scrollable): __gtype_name__ = "SDAPSSheetWidget" def __init__(self, provider): Gtk.DrawingArea.__init__(self) events = Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.BUTTON_RELEASE_MASK | \ Gdk.EventMask.POINTER_MOTION_MASK | Gdk.EventMask.BUTTON_MOTION_MASK | \ Gdk.EventMask.SCROLL_MASK | Gdk.EventMask.KEY_PRESS_MASK try: events = events | Gdk.EventMask.SMOOTH_SCROLL_MASK except AttributeError: # Does only work for GTK+ >=3.4 pass self.add_events(events) self.hadj = None self.vadj = None self._hadj_value_changed_cb_id = None self._vadj_value_changed_cb_id = None self.provider = provider self._old_scroll_x = 0 self._old_scroll_y = 0 self._edge_drag_active = False self._zoom = 1.0 self.props.can_focus = True self._update_matrices() self._cs_image = None self._ss_image = None self.provider.survey.questionnaire.connect_data_changed(self.partial_update) def update_state(self): # Cancel any dragging operation self._edge_drag_active = False self._update_matrices() self.queue_resize() self.queue_draw() def partial_update(self, questionnaire, qobj, obj, name, old_value): if qobj is None and name == "raw_matrix": self._update_matrices() self.queue_draw() return if not isinstance(obj, model.data.Box): return if self.provider.image.page_number != qobj.page_number: return self.invalidate_area(obj.x, obj.y, obj.width, obj.height) def _update_matrices(self): xoffset = 0 yoffset = 0 if self.hadj: xoffset = int(self.hadj.props.value) if self.vadj: yoffset = int(self.vadj.props.value) m = cairo.Matrix(self._zoom, 0, 0, self._zoom, -xoffset, -yoffset) form_matrix = self.provider.image.matrix.mm_to_px() m = form_matrix.multiply(m) self._mm_to_widget_matrix = m self._widget_to_mm_matrix = \ cairo.Matrix(*m) self._widget_to_mm_matrix.invert() def invalidate_area(self, x_mm, y_mm, width_mm, height_mm): x, y = self._mm_to_widget_matrix.transform_point(x_mm, y_mm) width, height = self._mm_to_widget_matrix.transform_distance(width_mm, height_mm) width = int(math.ceil(width + x - int(x))) + 20 height = int(math.ceil(height + y - int(y))) + 20 x = int(x) - 10 y = int(y) - 10 self.queue_draw_area(x, y, width, height) def _adjustment_changed_cb(self, adjustment): dx = int(self._old_scroll_x) - int(self.hadj.props.value) dy = int(self._old_scroll_y) - int(self.vadj.props.value) if self.get_window() is not None: self.get_window().scroll(dx, dy) self._old_scroll_x = self.hadj.props.value self._old_scroll_y = self.vadj.props.value # Update the transformation matrices self._update_matrices() def do_button_press_event(self, event): # Pass everything except normal clicks down if event.button != 1 and event.button != 2 and event.button != 3: return False if event.button == 2: self._drag_start_x = event.x self._drag_start_y = event.y cursor = Gdk.Cursor(Gdk.CursorType.HAND2) self.get_window().set_cursor(cursor) return True mm_x, mm_y = self._widget_to_mm_matrix.transform_point(event.x, event.y) if event.button == 3: # Give the corresponding widget the focus. box = self.provider.survey.questionnaire.gui.find_box(self.provider.image, mm_x, mm_y) if hasattr(box, "widget"): box.widget.focus() return True # button 1 self.grab_focus() # Look for edges to drag first(on a 4x4px target) tollerance_x, tollerance_y = self._widget_to_mm_matrix.transform_distance(4.0, 4.0) result = self.provider.survey.questionnaire.gui.find_edge(self.provider.image, mm_x, mm_y, tollerance_x, tollerance_y) if result: self.queue_draw() self._edge_drag_active = True self._edge_drag_obj = result[0] self._edge_drag_data = result[1] return True box = self.provider.survey.questionnaire.gui.find_box(self.provider.image, mm_x, mm_y) if box is not None: box.data.state = not box.data.state return True def do_button_release_event(self, event): if event.button != 1 and event.button != 2 and event.button != 3: return False self.get_window().set_cursor(None) if event.button == 1: self._edge_drag_active = False return True def do_motion_notify_event(self, event): if event.state & Gdk.ModifierType.BUTTON2_MASK: x = int(event.x) y = int(event.y) dx = self._drag_start_x - x dy = self._drag_start_y - y if self.hadj: value = self.hadj.props.value + dx value = min(value, self.hadj.props.upper - self.hadj.props.page_size) self.hadj.set_value(value) if self.vadj: value = self.vadj.props.value + dy value = min(value, self.vadj.props.upper - self.vadj.props.page_size) self.vadj.set_value(value) self._drag_start_x = event.x self._drag_start_y = event.y return True elif event.state & Gdk.ModifierType.BUTTON1_MASK: if self._edge_drag_active: mm_x, mm_y = self._widget_to_mm_matrix.transform_point(event.x, event.y) self._edge_drag_obj.gui.move_edge(self._edge_drag_data, mm_x, mm_y) self.queue_draw() return True return False def do_get_request_mode(self): return Gtk.SizeRequestMode.CONSTANT_SIZE def do_get_preferred_height(self): if self.vadj: self.vadj.props.upper = self._render_height return min(self._render_height, 300), self._render_height def do_get_preferred_width(self): if self.hadj: self.hadj.props.upper = self._render_width return min(self._render_width, 300), self._render_width def do_size_allocate(self, allocation): # WTF? Why does this happen? if allocation.x < 0 or allocation.y < 0: GObject.idle_add(self.queue_resize) if self.hadj: self.hadj.props.page_size = min(self._render_width, allocation.width) if self.hadj.props.value > self._render_width - allocation.width: self.hadj.props.value = self._render_width - allocation.width self.hadj.props.page_increment = allocation.width * 0.9 self.hadj.props.step_increment = allocation.width * 0.1 if self.vadj: self.vadj.props.page_size = min(self._render_height, allocation.height) if self.vadj.props.value > self._render_height - allocation.height: self.vadj.props.value = self._render_height - allocation.height self.vadj.props.page_increment = allocation.height * 0.9 self.vadj.props.step_increment = allocation.height * 0.1 self._update_matrices() Gtk.DrawingArea.do_size_allocate(self, allocation) def do_draw(self, cr): cr.save() cr.save() # For the image xoffset = -int(self.hadj.props.value) yoffset = -int(self.vadj.props.value) image = self.provider.image.surface.surface_rgb if image != self._cs_image or self._ss_image is None: self._cs_image = image target = cr.get_target() self._ss_image = target.create_similar(cairo.CONTENT_COLOR, image.get_width(), image.get_height()) subcr = cairo.Context(self._ss_image) subcr.set_source_surface(self._cs_image) subcr.paint() # Draw the image in the background cr.translate(xoffset, yoffset) cr.scale(self._zoom, self._zoom) cr.set_source_surface(self._ss_image, 0, 0) cr.paint() cr.restore() # Set the matrix _after_ drawing the background pixbuf. cr.transform(self._mm_to_widget_matrix) # Draw the overlay stuff. self.provider.survey.questionnaire.gui.draw(cr, self.provider.image) def inner_box(cr, x, y, width, height): line_width = cr.get_line_width() cr.rectangle(x + line_width / 2.0, y + line_width / 2.0, width - line_width, height - line_width) if self.provider.survey.defs.style == 'classic': half_pt = 0.5 / 72.0 * 25.4 pt = 1.0 / 72.0 * 25.4 inner_box(cr, defs.corner_mark_left + defs.corner_box_padding - half_pt, defs.corner_mark_top + defs.corner_box_padding - half_pt, defs.corner_box_width + pt, defs.corner_box_height + pt) inner_box(cr, self.provider.survey.defs.paper_width - defs.corner_mark_right - defs.corner_box_padding - defs.corner_box_width - half_pt, defs.corner_mark_top + defs.corner_box_padding - half_pt, defs.corner_box_width + pt, defs.corner_box_height + pt) inner_box(cr, defs.corner_mark_left + defs.corner_box_padding - half_pt, self.provider.survey.defs.paper_height - defs.corner_mark_bottom - defs.corner_box_padding - defs.corner_box_height - half_pt, defs.corner_box_width + pt, defs.corner_box_height + pt) inner_box(cr, self.provider.survey.defs.paper_width - defs.corner_mark_right - defs.corner_box_padding - defs.corner_box_width - half_pt, self.provider.survey.defs.paper_height - defs.corner_mark_bottom - defs.corner_box_padding - defs.corner_box_height - half_pt, defs.corner_box_width + pt, defs.corner_box_height + pt) cr.stroke() cr.restore() return True def do_key_press_event(self, event): if self.vadj: if event.keyval == Gdk.keyval_from_name("Up"): value = self.vadj.props.value - self.vadj.props.step_increment value = min(value, self.vadj.props.upper - self.vadj.props.page_size) self.vadj.set_value(value) return True if event.keyval == Gdk.keyval_from_name("Down"): value = self.vadj.props.value + self.vadj.props.step_increment value = min(value, self.vadj.props.upper - self.vadj.props.page_size) self.vadj.set_value(value) return True if self.hadj: if event.keyval == Gdk.keyval_from_name("Left"): value = self.hadj.props.value - self.hadj.props.step_increment value = min(value, self.hadj.props.upper - self.hadj.props.page_size) self.hadj.set_value(value) return True if event.keyval == Gdk.keyval_from_name("Right"): value = self.hadj.props.value + self.hadj.props.step_increment value = min(value, self.hadj.props.upper - self.hadj.props.page_size) self.hadj.set_value(value) return True return False def _get_render_width(self): image = self.provider.image.surface.surface_rgb if image: width = image.get_width() else: width = 400 width = int(math.ceil(self._zoom * width)) return width def _get_render_height(self): image = self.provider.image.surface.surface_rgb if image: height = image.get_height() else: height = 400 height = int(math.ceil(self._zoom * height)) return height _render_width = property(_get_render_width) _render_height = property(_get_render_height) def get_hscroll_policy(self): # Does not matter, we don't support natural sizes return Gtk.ScrollablePolicy.NATURAL hscroll_policy = \ GObject.property(get_hscroll_policy, type=Gtk.ScrollablePolicy, default=Gtk.ScrollablePolicy.NATURAL) def get_vscroll_policy(self): # Does not matter, we don't support natural sizes return Gtk.ScrollablePolicy.NATURAL vscroll_policy = \ GObject.property(get_vscroll_policy, type=Gtk.ScrollablePolicy, default=Gtk.ScrollablePolicy.NATURAL) def get_vadjustment(self): return self.vadj def set_vadjustment(self, value): if self._vadj_value_changed_cb_id is not None: self.vadj.disconnect(self._vadj_value_changed_cb_id) self._vadj_value_changed_cb_id = None self.vadj = value if self.vadj is not None: self._vadj_value_changed_cb_id = self.vadj.connect('value-changed', self._adjustment_changed_cb) self._update_matrices() vadjustment = GObject.property(get_vadjustment, set_vadjustment, type=Gtk.Adjustment) def get_hadjustment(self): return self.hadj def set_hadjustment(self, value): if self._hadj_value_changed_cb_id is not None: self.hadj.disconnect(self._hadj_value_changed_cb_id) self._hadj_value_changed_cb_id = None self.hadj = value if self.hadj is not None: self._hadj_value_changed_cb_id = self.hadj.connect('value-changed', self._adjustment_changed_cb) self._update_matrices() hadjustment = GObject.property(get_hadjustment, set_hadjustment, type=Gtk.Adjustment) def set_zoom(self, value): self._zoom = value self.queue_resize() def get_zoom(self): return self._zoom zoom = GObject.property(get_zoom, set_zoom, float, minimum=0.001, maximum=1024.0, default=1.0) sdaps-1.9.8/sdaps/gui/widget_buddies.py0000644000175000000660000003226713521032407020640 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from gi.repository import Gtk from gi.repository import GLib, GObject import cairo from sdaps import model from sdaps import defs from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext def markup_escape_text(text): # Unfortunately the API returns a byte string, so we need to decode it # as the formatting would not work otherwise. return GLib.markup_escape_text(text) class Questionnaire(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'widget' obj_class = model.questionnaire.Questionnaire def __init__(self, *args): model.buddy.Buddy.__init__(self, *args) self.obj.connect_data_changed(self.data_changed) self._current_image = None self._notify_ensure_visible = list() def data_changed(self, questionnaire, qobj, obj, name, old_value): # Simply sync everything on every change. self.sync_state() def create_widget(self): self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) # First some global options widget = Gtk.Label() widget.set_markup(_('Global Properties')) widget.props.xalign = 0.0 self.box.pack_start(widget, False, True, 0) self.valid_checkbox = Gtk.CheckButton.new_with_label(_('Sheet valid')) self.sheet_verified_checkbox = Gtk.CheckButton.new_with_label(_('Sheet Verified')) self.page_verified_checkbox = Gtk.CheckButton.new_with_label(_('Page Verified')) self.empty_checkbox = Gtk.CheckButton.new_with_label(_('Empty')) self.empty_checkbox.set_sensitive(False) frame = Gtk.Frame() self.review_textbox = Gtk.TextView() self.review_textbox.set_wrap_mode(Gtk.WrapMode.WORD_CHAR) self.review_buffer = self.review_textbox.get_buffer() self.review_buffer.connect('changed', self.review_buffer_changed_cb) frame.add(self.review_textbox) self.review_comments = Gtk.CheckButton.new_with_label(_('Empty')) self.valid_checkbox.connect('toggled', self.toggled_valid_cb) self.page_verified_checkbox.connect('toggled', self.toggled_verified_cb) indent = Gtk.Alignment() indent.set_padding(0, 0, 10, 0) vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.qid = Gtk.Label() self.qid.set_markup(_('Questionnaire ID: ') + markup_escape_text(str(self.obj.survey.sheet.questionnaire_id))) self.qid.props.xalign = 0.0 indent.add(vbox) vbox.add(self.qid) vbox.add(self.valid_checkbox) vbox.add(self.sheet_verified_checkbox) vbox.add(self.page_verified_checkbox) vbox.add(self.empty_checkbox) vbox.add(frame) self.box.pack_start(indent, False, True, 0) # And all the questions for qobject in self.obj.qobjects: widget = qobject.widget.create_widget() if widget is not None: self.box.pack_start(widget, False, True, 0) return self.box def sync_state(self, image=None): # This is to keep track of the currently active image. if image: self._current_image = image assert self._current_image in self.obj.survey.sheet.images for qobject in self.obj.qobjects: qobject.widget.sync_state() self.qid.set_markup(_('Questionnaire ID: ') + markup_escape_text(str(self.obj.survey.sheet.questionnaire_id))) self.valid_checkbox.set_active(self.obj.survey.sheet.valid) self.sheet_verified_checkbox.set_active(self.obj.survey.sheet.verified) self.page_verified_checkbox.set_active(self._current_image.verified) self.empty_checkbox.set_active(self.obj.survey.sheet.empty) # Only update the text if it changed (or else recursion hits) start = self.review_buffer.get_start_iter() end = self.review_buffer.get_end_iter() currtext = self.review_buffer.get_text(start, end, False) review_comment = self.obj.survey.sheet.review_comment if self.obj.survey.sheet.review_comment else '' if review_comment != currtext: self.review_buffer.set_text(review_comment) def ensure_visible(self, widget): for func in self._notify_ensure_visible: func(widget) def connect_ensure_visible(self, func): self._notify_ensure_visible.append(func) def disconnect_ensure_visible(self, func): self._notify_ensure_visible.remove(func) def review_buffer_changed_cb(self, buf): start = self.review_buffer.get_start_iter() end = self.review_buffer.get_end_iter() currtext = self.review_buffer.get_text(start, end, False) self.obj.survey.sheet.review_comment = currtext def toggled_valid_cb(self, widget): self.obj.survey.sheet.valid = widget.get_active() def toggled_verified_cb(self, widget): self._current_image.verified = widget.get_active() class QObject(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'widget' obj_class = model.questionnaire.QObject def create_widget(self): self.widget = None self.review_buffer = None return self.widget def make_heading(self, title): vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) vbox.set_margin_top(12) hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) label = Gtk.Label() label.set_markup('%s %s' % (self.obj.id_str(), markup_escape_text(title))) label.set_halign(Gtk.Align.START) label.show() hbox.add(label) image = Gtk.Image() image.set_from_icon_name('document-edit-symbolic', Gtk.IconSize.BUTTON) toggle = Gtk.ToggleButton(image=image) toggle.set_halign(Gtk.Align.END) toggle.set_margin_start(12) hbox.add(toggle) image.connect("button-press-event", lambda *args: print(pressed)) vbox.add(hbox) self.review_frame = Gtk.Frame() self.review_frame.set_margin_start(12) self.review_textbox = Gtk.TextView() self.review_textbox.show() self.review_textbox.set_wrap_mode(Gtk.WrapMode.WORD_CHAR) self.review_buffer = self.review_textbox.get_buffer() self.review_buffer.connect('changed', self.review_buffer_changed_cb) self.review_frame.add(self.review_textbox) self.review_frame.hide() self.review_frame.set_no_show_all(True) vbox.add(self.review_frame) toggle.bind_property("active", self.review_frame, "visible", GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.BIDIRECTIONAL) return vbox def sync_state(self): for box in self.obj.boxes: box.widget.sync_state() # Only update the text if it changed (or else recursion hits) if self.review_buffer: start = self.review_buffer.get_start_iter() end = self.review_buffer.get_end_iter() currtext = self.review_buffer.get_text(start, end, False) review_comment = self.obj.data.review_comment if self.obj.data.review_comment else '' if review_comment != currtext: self.review_frame.set_visible(bool(review_comment)) self.review_buffer.set_text(review_comment) def focus(self): self.obj.question.questionnaire.widget.ensure_visible(self.widget) if len(boxes) > 0: self.obj.boxes[0].widget.focus() def review_buffer_changed_cb(self, buf): start = self.review_buffer.get_start_iter() end = self.review_buffer.get_end_iter() currtext = self.review_buffer.get_text(start, end, False) self.obj.data.review_comment = currtext class Head(QObject, metaclass=model.buddy.Register): name = 'widget' obj_class = model.questionnaire.Head def create_widget(self): self.widget = self.make_heading(self.obj.title) return self.widget class Question(QObject, metaclass=model.buddy.Register): name = 'widget' obj_class = model.questionnaire.Question def create_widget(self): self.widget = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.label = self.make_heading(self.obj.question) self.widget.pack_start(self.label, False, True, 0) vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) vbox.set_margin_start(12) self.widget.pack_end(vbox, False, True, 0) for box in self.obj.boxes: widget = box.widget.create_widget() if widget is not None: vbox.pack_start(widget, False, True, 0) return self.widget class Range(Question, metaclass=model.buddy.Register): name = 'widget' obj_class = model.questionnaire.Range def create_widget(self): self.widget = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.label = self.make_heading(self.obj.question) self.widget.pack_start(self.label, False, True, 0) hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) lower_label = Gtk.Label() lower_label.set_text(self.obj.answers[0]) lower_label.props.xalign = 1.0 upper_label = Gtk.Label() upper_label.set_text(self.obj.answers[1]) upper_label.props.xalign = 0.0 sizegroup = Gtk.SizeGroup() sizegroup.set_mode(Gtk.SizeGroupMode.BOTH) sizegroup.add_widget(lower_label) sizegroup.add_widget(upper_label) hbox.pack_start(lower_label, True, True, 0) # Maybe use radiobuttons instead? for box in self.obj.boxes: widget = box.widget.create_widget() if widget is not None: hbox.pack_start(widget, False, True, 0) hbox.pack_start(upper_label, True, True, 0) self.widget.pack_start(hbox, False, True, 0) return self.widget class Box(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'widget' obj_class = model.questionnaire.Checkbox def create_widget(self): if self.obj.text: self.widget = Gtk.CheckButton.new_with_label(self.obj.text) else: self.widget = Gtk.CheckButton.new_with_label('') self.widget.connect('toggled', self.toggled_cb) return self.widget def sync_state(self): self.widget.props.active = self.obj.data.state def toggled_cb(self, widget): self.obj.data.state = widget.props.active def focus(self): self.widget.grab_focus() self.obj.question.questionnaire.widget.ensure_visible(self.obj.question.widget.widget) self.obj.question.questionnaire.widget.ensure_visible(self.widget) class Checkbox(Box, metaclass=model.buddy.Register): name = 'widget' obj_class = model.questionnaire.Checkbox class Textbox(Box, metaclass=model.buddy.Register): name = 'widget' obj_class = model.questionnaire.Textbox def create_widget(self): self.widget = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.checkbox = Gtk.CheckButton.new_with_label(self.obj.text) self.checkbox.connect('toggled', self.toggled_cb) self.widget.add(self.checkbox) frame = Gtk.Frame() frame.set_margin_start(12) self.widget.pack_end(frame, False, True, 0) self.textbox = Gtk.TextView() self.textbox.set_wrap_mode(Gtk.WrapMode.WORD_CHAR) self.buffer = self.textbox.get_buffer() self.buffer.connect('changed', self.buffer_changed_cb) frame.add(self.textbox) return self.widget def buffer_changed_cb(self, buf): start = buf.get_start_iter() end = buf.get_end_iter() self.obj.data.text = buf.get_text(start, end, False) def sync_state(self): self.checkbox.props.active = self.obj.data.state self.textbox.props.sensitive = self.obj.data.state # Only update the text if it changed (or else recursion hits) start = self.buffer.get_start_iter() end = self.buffer.get_end_iter() currtext = self.buffer.get_text(start, end, False) text = self.obj.data.text if self.obj.data.text else '' if text != currtext: self.buffer.set_text(text) def focus(self): if self.textbox.props.sensitive: self.textbox.grab_focus() else: self.checkbox.grab_focus() self.obj.question.questionnaire.widget.ensure_visible(self.obj.question.widget.widget) self.obj.question.questionnaire.widget.ensure_visible(self.widget) sdaps-1.9.8/sdaps/image/0000755000175000000660000000000013611127124015571 5ustar benjaminlock00000000000000sdaps-1.9.8/sdaps/image/__init__.py0000644000175000000660000001307213575707425017726 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """ This modules contains low level image processing functions. These functions are implemented in C for speed reasons. Usually one will not need to use these directly, instead modules like "recognize" or "surface" use them to load and analyze the image data. """ import os import sys import cairo from sdaps import paths from sdaps import defs from sdaps import log from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext if paths.local_run: # image.so liegt in lib_build_dir/image/ __path__.append(os.path.join(paths.lib_build_dir, 'image')) # If SDAPS is installed, then the image.so file is in the current directory. # Simply importing it without changes to the paths will work. try: from .image import * except ImportError as e: print(e) log.error(_("It appears you have not build the C extension. Please run \"./setup.py build\" in the toplevel directory.")) sys.exit(1) set_magic_values(defs.corner_mark_min_length, defs.corner_mark_max_length, defs.image_line_width, defs.corner_mark_search_distance, defs.image_line_coverage) # Offset into corners, not valid for C API which has +1 as offset! TOP_LEFT = 0 TOP_RIGHT = 1 BOTTOM_RIGHT = 2 BOTTOM_LEFT = 3 def calculate_matrix(surface, matrix, mm_x, mm_y, mm_width, mm_height): """Detect the transformation matrix This runs a detection for the corner marks that denote the bounding box given by mm_x, mm_y, mm_width, mm_height in the surface. The passed matrix is used for to estimate the resolution of the image. This function returns a new cairo matrix or raises an error otherwise. """ found_corners = 0 corners = [] for i in (1, 2, 3, 4): try: corners.append(find_corner_marker (surface, matrix, i)) found_corners += 1 except: corners.append(None) # We need at least 3 corners to do anything assert found_corners >= 3 return matrix_from_corners_2d(corners, mm_x, mm_y, mm_width, mm_height) def matrix_from_corners_2d(corners, mm_x, mm_y, mm_width, mm_height): """Calculate the transformation matrix from bounding box corners Given the list of corners in the order top left, top right, bottom right, bottom left in px space and the bounding box that is defined by these corners in mm space, calcualte the corresponding px to mm transformation matrix. This function returns a new cairo matrix or raises an error otherwise. """ assert len(corners) == 4 assert corners.count(None) <= 1 # Calculate a new "perfect" location for the undefined corner if corners[TOP_LEFT] is None: corners[TOP_LEFT] = ( corners[BOTTOM_LEFT][0] - corners[BOTTOM_RIGHT][0] + corners[TOP_RIGHT][0], corners[TOP_RIGHT][1] - corners[BOTTOM_RIGHT][1] + corners[BOTTOM_LEFT][1] ) if corners[TOP_RIGHT] is None: corners[TOP_RIGHT] = ( corners[BOTTOM_RIGHT][0] - corners[BOTTOM_LEFT][0] + corners[TOP_LEFT][0], corners[TOP_LEFT][1] - corners[BOTTOM_LEFT][1] + corners[BOTTOM_RIGHT][1] ) if corners[BOTTOM_LEFT] is None: corners[BOTTOM_LEFT] = ( corners[TOP_LEFT][0] - corners[TOP_RIGHT][0] + corners[BOTTOM_RIGHT][0], corners[BOTTOM_RIGHT][1] - corners[TOP_RIGHT][1] + corners[TOP_LEFT][1] ) if corners[BOTTOM_RIGHT] is None: corners[BOTTOM_RIGHT] = ( corners[TOP_RIGHT][0] - corners[TOP_LEFT][0] + corners[BOTTOM_LEFT][0], corners[BOTTOM_LEFT][1] - corners[TOP_LEFT][1] + corners[TOP_RIGHT][1] ) # X-Axis dx = ((corners[TOP_RIGHT][0] - corners[TOP_LEFT][0]) + (corners[BOTTOM_RIGHT][0] - corners[BOTTOM_LEFT][0])) / 2 dy = ((corners[TOP_RIGHT][1] - corners[TOP_LEFT][1]) + (corners[BOTTOM_RIGHT][1] - corners[BOTTOM_LEFT][1])) / 2 xx = dx / mm_width yx = dy / mm_width # y-Axis dx = ((corners[BOTTOM_RIGHT][0] - corners[TOP_RIGHT][0]) + (corners[BOTTOM_LEFT][0] - corners[TOP_LEFT][0])) / 2 dy = ((corners[BOTTOM_RIGHT][1] - corners[TOP_RIGHT][1]) + (corners[BOTTOM_LEFT][1] - corners[TOP_LEFT][1])) / 2 xy = dx / mm_height yy = dy / mm_height # Center everything between the markers x0 = (corners[BOTTOM_LEFT][0] + corners[BOTTOM_RIGHT][0] + corners[TOP_LEFT][0] + corners[TOP_RIGHT][0]) / 4 y0 = (corners[BOTTOM_LEFT][1] + corners[BOTTOM_RIGHT][1] + corners[TOP_LEFT][1] + corners[TOP_RIGHT][1]) / 4 x_center = mm_width / 2 + mm_x y_center = mm_height / 2 + mm_y dx = x_center * xx + y_center * xy dy = x_center * yx + y_center * yy x0 -= dx y0 -= dy m_new = cairo.Matrix(xx, yx, xy, yy, x0, y0) m_new.invert() return m_new sdaps-1.9.8/sdaps/image/image.c0000644000175000000660000010545713575707425017054 0ustar benjaminlock00000000000000/* SDAPS * Copyright (C) 2008 Christoph Simon * Copyright (C) 2008, 2011 Benjamin Berg * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /*#include */ #include #include "image.h" #include #include "surface.h" #include "transform.h" /* Some of the more important Magic Values */ gdouble sdaps_line_min_length = 20-2; gdouble sdaps_line_max_length = 20+2; gdouble sdaps_line_width = 1/72*25.4; gdouble sdaps_corner_mark_search_distance = 50; gdouble sdaps_line_coverage = 0.65; gboolean sdaps_create_debug_surface = FALSE; gint sdaps_debug_surface_ox; gint sdaps_debug_surface_oy; cairo_surface_t *sdaps_debug_surface = NULL; static void debug_surface_clear(void) { if (sdaps_debug_surface != NULL) { cairo_surface_destroy(sdaps_debug_surface); sdaps_debug_surface = NULL; } } static cairo_surface_t* debug_surface_create(gint x, gint y, gint width, gint height, gdouble r, gdouble g, gdouble b, gdouble a) { cairo_t* cr; debug_surface_clear(); if (!sdaps_create_debug_surface) return NULL; sdaps_debug_surface_ox = x; sdaps_debug_surface_oy = y; sdaps_debug_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); cr = cairo_create (sdaps_debug_surface); cairo_set_source_rgba (cr, r, g, b, a); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_paint (cr); cairo_destroy (cr); cairo_surface_flush (sdaps_debug_surface); return sdaps_debug_surface; } void disable_libtiff_warnings (void) { TIFFSetWarningHandler(NULL); } cairo_surface_t* get_a1_from_tiff (const char *filename, gint page, gboolean rotated) { TIFF* tiff; cairo_surface_t *surface; guint32 *s_pixels; guint32 *t_pixels; guint32 *t_row; int s_stride, t_stride; int width, height; BARREL_VARS int x, y; tiff = TIFFOpen(filename, "r"); if (tiff == NULL) return NULL; if (!TIFFSetDirectory(tiff, page)) { TIFFClose(tiff); return NULL; } TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &height); t_pixels = g_new(guint32, width * height); if (!rotated) TIFFReadRGBAImageOriented(tiff, width, height, t_pixels, ORIENTATION_TOPLEFT, 0); else TIFFReadRGBAImageOriented(tiff, width, height, t_pixels, ORIENTATION_BOTRIGHT, 0); surface = cairo_image_surface_create(CAIRO_FORMAT_A1, width, height); s_pixels = (guint32*) cairo_image_surface_get_data(surface); s_stride = cairo_image_surface_get_stride(surface); t_stride = width * sizeof(guint32); t_row = t_pixels; for (y = 0; y < height; y++) { guint32 *t_p = t_row; BARREL_START_ROW((char*)s_pixels + y * s_stride) for (x = 0; x < width; x++) { BARREL_STORE_BIT(!(TIFFGetR(*t_p) >> 7)); /* SET_PIXEL(s_pixels, s_stride, x, y, !(TIFFGetR(*t_p) >> 7)); */ t_p = t_p + 1; } BARREL_FLUSH t_row = (guint32*) ((char*) t_row + t_stride); } g_free(t_pixels); TIFFClose(tiff); cairo_surface_mark_dirty(surface); return surface; } gboolean write_a1_to_tiff (const char *filename, cairo_surface_t *surf) { TIFF *tiff; gint width, height; gint stride; gint y; guint32 stripsize; guint8 *data; g_assert(cairo_image_surface_get_format(surf) == CAIRO_FORMAT_A1); width = cairo_image_surface_get_width(surf); height = cairo_image_surface_get_height(surf); stride = cairo_image_surface_get_stride(surf); data = (guint8*) cairo_image_surface_get_data(surf); /* We create a new TIFF file if it doesn't exist yet, otherwise we append * to it. */ tiff = TIFFOpen(filename, "a"); if (tiff == NULL) return FALSE; /* Reverse *ALL* bits ... * TODO: Is this correct for big endian??? */ TIFFReverseBits(data, stride*(height-1) + (width+7)/8); /* Setup the new image. */ TIFFSetField(tiff, TIFFTAG_IMAGEWIDTH, width); TIFFSetField(tiff, TIFFTAG_IMAGELENGTH, height); TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 1); TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, 1); TIFFSetField(tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_SEPARATE); stripsize = TIFFDefaultStripSize(tiff, -1); TIFFSetField(tiff, TIFFTAG_ROWSPERSTRIP, stripsize); TIFFSetField(tiff, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX4); TIFFSetField(tiff, TIFFTAG_GROUP4OPTIONS, 0); TIFFSetField(tiff, TIFFTAG_FAXMODE, FAXMODE_CLASSF); TIFFSetField(tiff, TIFFTAG_THRESHHOLDING, THRESHHOLD_BILEVEL); TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE); for (y = 0; y < height; y++) { if (TIFFWriteScanline(tiff, data + y * stride, y, 0) == -1) goto BAIL_WRITE_A1; } /* Undo reversal again. */ TIFFReverseBits(data, stride*(height-1) + (width+7)/8); TIFFClose(tiff); return TRUE; BAIL_WRITE_A1: /* Undo reversal again. */ TIFFReverseBits(data, stride*(height-1) + (width+7)/8); TIFFClose(tiff); return FALSE; } cairo_surface_t* get_rgb24_from_tiff (const char *filename, gint page, gboolean rotated) { TIFF* tiff; cairo_surface_t *surface; guint32 *s_pixels; guint32 *t_pixels; guint32 *t_row; int s_stride, t_stride; int width, height; int x, y; tiff = TIFFOpen(filename, "r"); if (tiff == NULL) return NULL; if (!TIFFSetDirectory(tiff, page)) { TIFFClose(tiff); return NULL; } TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &height); t_pixels = g_new(guint32, width * height); if (!rotated) TIFFReadRGBAImageOriented(tiff, width, height, t_pixels, ORIENTATION_TOPLEFT, 0); else TIFFReadRGBAImageOriented(tiff, width, height, t_pixels, ORIENTATION_BOTRIGHT, 0); surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height); s_pixels = (guint32*) cairo_image_surface_get_data(surface); s_stride = cairo_image_surface_get_stride(surface); t_stride = width * sizeof(guint32); t_row = t_pixels; for (y = 0; y < height; y++) { guint32 *t_p = t_row; for (x = 0; x < width; x++) { *((guint32*) (((guint8*) s_pixels) + 4 * x + y * s_stride)) = (TIFFGetR(*t_p) << 16) | (TIFFGetG(*t_p) << 8) | TIFFGetB(*t_p); t_p = t_p + 1; } t_row = (guint32*) ((char*) t_row + t_stride); } g_free(t_pixels); TIFFClose(tiff); cairo_surface_mark_dirty(surface); return surface; } gint get_tiff_page_count (const char *filename) { TIFF* tiff; gint pages; tiff = TIFFOpen(filename, "r"); if (tiff == NULL) return 0; pages = TIFFNumberOfDirectories(tiff); TIFFClose(tiff); return pages; } gboolean get_tiff_resolution (const char *filename, gint page, gdouble *xresolution, gdouble *yresolution) { TIFF* tiff; float xres = 0.0; float yres = 0.0; uint16 unit = RESUNIT_NONE; tiff = TIFFOpen(filename, "r"); if (tiff == NULL) return FALSE; if (!TIFFSetDirectory(tiff, page)) { TIFFClose(tiff); return FALSE; } TIFFGetField(tiff, TIFFTAG_XRESOLUTION, &xres); TIFFGetField(tiff, TIFFTAG_YRESOLUTION, &yres); TIFFGetField(tiff, TIFFTAG_RESOLUTIONUNIT, &unit); if (unit == RESUNIT_CENTIMETER) { *xresolution = xres / 10.0; *yresolution = yres / 10.0; } else if (unit == RESUNIT_INCH) { *xresolution = xres / 25.4; *yresolution = yres / 25.4; } else { /* Nothing good, pass back zeros */ *xresolution = 0; *yresolution = 0; } TIFFClose(tiff); return TRUE; } gboolean check_tiff_monochrome (const char *filename) { TIFF* tiff; gboolean monochrome = TRUE; tiff = TIFFOpen(filename, "r"); if (tiff == NULL) return FALSE; do { uint16 bits_per_sample; TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bits_per_sample); if (bits_per_sample != 1) monochrome = FALSE; } while (TIFFReadDirectory(tiff) && monochrome); if (!TIFFLastDirectory(tiff)) { /* This should never ever happen ... */ monochrome = FALSE; } TIFFClose(tiff); return monochrome; } #define LINE_COVERAGE sdaps_line_coverage static gint transform_distance_to_pixel(cairo_matrix_t *matrix, gdouble distance) { gdouble dx, dy; dx = distance; dy = distance; cairo_matrix_transform_distance(matrix, &dx, &dy); return (gint) ceil(MAX(dx, dy)); } static gboolean follow_line(cairo_surface_t *surface, gint x_start, gint y_start, gint x_dir, gint y_dir, gint line_width, gint line_length, gint line_max_length, gdouble *x1, gdouble *y1, gdouble *x2, gdouble *y2) { gboolean found_segment; gboolean found_line = FALSE; gint x, y; gint start_x, start_y; gint end_x, end_y; double length = 0; gint search_length_left; /* Large default values to begin with. These may not overflow when added up! */ start_x = 100000; start_y = 100000; end_x = 0; end_y = 0; found_segment = TRUE; /* ****** Positive Direction */ x = x_start; y = y_start; search_length_left = 2*line_width; while (found_segment || search_length_left > 0) { gint offset; gint found_offset = 0; gint coverage; gint max_coverage = 0; search_length_left -= 1; x += x_dir; y += y_dir; found_segment = FALSE; for (offset = -line_width; offset <= line_width; offset++) { gint coverage_1, coverage_2, coverage_3; coverage_1 = count_black_pixel(surface, x + offset * y_dir - line_width / 2, y + offset * x_dir - line_width / 2, line_width, line_width); coverage_2 = count_black_pixel(surface, x - line_width*x_dir + offset * y_dir - line_width / 2, y - line_width*y_dir + offset * x_dir - line_width / 2, line_width, line_width); coverage_3 = count_black_pixel(surface, x + line_width*x_dir + offset * y_dir - line_width / 2, y + line_width*y_dir + offset * x_dir - line_width / 2, line_width, line_width); if (coverage_1 < (line_width * line_width) * LINE_COVERAGE) continue; if (coverage_2 < (line_width * line_width) * LINE_COVERAGE) continue; if (coverage_3 < (line_width * line_width) * LINE_COVERAGE) continue; coverage = coverage_1 + coverage_2 + coverage_3; if ((coverage >= (3*line_width * line_width) * LINE_COVERAGE) && (coverage > max_coverage)) { gint p_x, p_y, cov_area; /* Is this really a "line", ie. is the surrounding area *not* dark. */ cov_area = count_black_pixel(surface, x + offset * y_dir - line_width - line_width / 2, y + offset * x_dir - line_width - line_width / 2, line_width * 3, line_width * 3); if ((abs(x - start_x + y - start_y) > line_width*1.5) && cov_area >= 2*coverage) continue; found_segment = TRUE; found_offset = offset; max_coverage = coverage; search_length_left = 0; p_x = x - line_width*ABS(x_dir) + offset * y_dir; p_y = y - line_width*ABS(y_dir) + offset * x_dir; if (ABS(start_x * x_dir + start_y * y_dir) > ABS(p_x * x_dir + p_y * y_dir)) { start_x = p_x; start_y = p_y; } p_x = x + line_width*ABS(x_dir) + offset * y_dir; p_y = y + line_width*ABS(y_dir) + offset * x_dir; if (ABS(end_x * x_dir + end_y * y_dir) < ABS(p_x * x_dir + p_y * y_dir)) { end_x = p_x; end_y = p_y; } } } x += found_offset * y_dir; y += found_offset * x_dir; length = sqrt((start_x - end_x)*(start_x - end_x) + (start_y - end_y)*(start_y - end_y)); if (length >= line_max_length) goto FOLLOW_LINE_BAIL; } /* ****** Negative Direction */ x = x_start; y = y_start; found_segment = TRUE; search_length_left = 2*line_width; while (found_segment || search_length_left > 0) { gint offset; gint found_offset = 0; gint coverage; gint max_coverage = 0; search_length_left -= 1; x -= x_dir; y -= y_dir; found_segment = FALSE; for (offset = -line_width; (offset <= line_width) && !found_segment; offset++) { gint coverage_1, coverage_2, coverage_3; coverage_1 = count_black_pixel(surface, x + offset * y_dir - line_width / 2, y + offset * x_dir - line_width / 2, line_width, line_width); coverage_2 = count_black_pixel(surface, x - line_width*x_dir + offset * y_dir - line_width / 2, y - line_width*y_dir + offset * x_dir - line_width / 2, line_width, line_width); coverage_3 = count_black_pixel(surface, x + line_width*x_dir + offset * y_dir - line_width / 2, y + line_width*y_dir + offset * x_dir - line_width / 2, line_width, line_width); if (coverage_1 < (line_width * line_width) * LINE_COVERAGE) continue; if (coverage_2 < (line_width * line_width) * LINE_COVERAGE) continue; if (coverage_3 < (line_width * line_width) * LINE_COVERAGE) continue; coverage = coverage_1 + coverage_2 + coverage_3; if ((coverage >= (3*line_width * line_width) * LINE_COVERAGE) && (coverage > max_coverage)) { gint p_x, p_y, cov_area; /* Is this really a "line", ie. is the surrounding area *not* dark. */ cov_area = count_black_pixel(surface, x + offset * y_dir - line_width - line_width / 2, y + offset * x_dir - line_width - line_width / 2, line_width * 3, line_width * 3); if ((abs(x - start_x + y - start_y) > line_width*1.5) && cov_area >= 2*coverage) continue; found_segment = TRUE; found_offset = offset; max_coverage = coverage; search_length_left = 0; p_x = x - line_width*ABS(x_dir) + offset * y_dir; p_y = y - line_width*ABS(y_dir) + offset * x_dir; if (ABS(start_x * x_dir + start_y * y_dir) > ABS(p_x * x_dir + p_y * y_dir)) { start_x = p_x; start_y = p_y; } p_x = x + line_width*ABS(x_dir) + offset * y_dir; p_y = y + line_width*ABS(y_dir) + offset * x_dir; if (ABS(end_x * x_dir + end_y * y_dir) < ABS(p_x * x_dir + p_y * y_dir)) { end_x = p_x; end_y = p_y; } } } x += found_offset * y_dir; y += found_offset * x_dir; length = sqrt((start_x - end_x)*(start_x - end_x) + (start_y - end_y)*(start_y - end_y)); if (length >= line_max_length) goto FOLLOW_LINE_BAIL; } found_line = length >= line_length; if (found_line) { gint offset; gdouble w1_x, w1_y; gdouble w2_x, w2_y; gdouble weight; x = (start_x * 3 + end_x) / 4; y = (start_y * 3 + end_y) / 4; w1_x = 0; w1_y = 0; weight = 0; for (offset = - 3 - line_width; offset <= 3 + line_width; offset++) { gint seg_weight; seg_weight = count_black_pixel(surface, x + offset * y_dir - MAX(ABS((line_length / 2 - line_width * 2) * x_dir), 1) / 2, y + offset * x_dir - MAX(ABS((line_length / 2 - line_width * 2) * y_dir), 1) / 2, MAX(ABS((line_length / 2 - line_width * 2) * x_dir), 1), MAX(ABS((line_length / 2 - line_width * 2) * y_dir), 1)); if (weight == 0) { /* this prevents a division by zero if seg_weight is 0 too. */ weight = seg_weight; w1_x = x + offset * y_dir + 0.5; w1_y = y + offset * x_dir + 0.5; } else { gdouble seg_x, seg_y; seg_x = x + offset * y_dir + 0.5; seg_y = y + offset * x_dir + 0.5; w1_x = w1_x * weight / (weight + seg_weight) + seg_x * seg_weight / (weight + seg_weight); w1_y = w1_y * weight / (weight + seg_weight) + seg_y * seg_weight / (weight + seg_weight); weight += seg_weight; } } x = (start_x + end_x * 3) / 4; y = (start_y + end_y * 3) / 4; w2_x = 0; w2_y = 0; weight = 0; for (offset = - 3 - line_width; offset <= 3 + line_width; offset++) { gint seg_weight; seg_weight = count_black_pixel(surface, x + offset * y_dir - MAX(ABS((line_length / 2 - line_width * 2) * x_dir), 1) / 2, y + offset * x_dir - MAX(ABS((line_length / 2 - line_width * 2) * y_dir), 1) / 2, MAX(ABS((line_length / 2 - line_width * 2) * x_dir), 1), MAX(ABS((line_length / 2 - line_width * 2) * y_dir), 1)); if (weight == 0) { /* this prevents a division by zero if seg_weight is 0 too. */ weight = seg_weight; w2_x = x + offset * y_dir + 0.5; w2_y = y + offset * x_dir + 0.5; } else { gdouble seg_x, seg_y; seg_x = x + offset * y_dir + 0.5; seg_y = y + offset * x_dir + 0.5; w2_x = w2_x * weight / (weight + seg_weight) + seg_x * seg_weight / (weight + seg_weight); w2_y = w2_y * weight / (weight + seg_weight) + seg_y * seg_weight / (weight + seg_weight); weight += seg_weight; } } /* got two points, now extrapolate them to the line start/end. */ *x1 = w1_x - (w2_x - w1_x) / 2.0; *y1 = w1_y - (w2_y - w1_y) / 2.0; *x2 = w2_x - (w1_x - w2_x) / 2.0; *y2 = w2_y - (w1_y - w2_y) / 2.0; } FOLLOW_LINE_BAIL: return found_line; } static void calc_intersection(gdouble l1a_x, gdouble l1a_y, gdouble l1b_x, gdouble l1b_y, gdouble l2a_x, gdouble l2a_y, gdouble l2b_x, gdouble l2b_y, gdouble *result_x, gdouble *result_y) { gdouble u; u = ((l2b_x - l2a_x)*(l1a_y - l2a_y) - (l2b_y - l2a_y)*(l1a_x - l2a_x)) / ((l2b_y - l2a_y)*(l1b_x - l1a_x) - (l2b_x - l2a_x)*(l1b_y - l1a_y)); *result_x = l1a_x + u*(l1b_x - l1a_x); *result_y = l1a_y + u*(l1b_y - l1a_y); } #define DIST(x1, y1, x2, y2) sqrt(((x1) - (x2))*((x1) - (x2)) + ((y1) - (y2))*((y1) - (y2))) static gboolean test_corner_marker(cairo_surface_t *surface, gint x, gint y, gint x_dir, gint y_dir, gint line_width, gint line_length, gint line_max_length, gdouble *x_result, gdouble *y_result) { gdouble h_x1, h_x2, h_y1, h_y2; gboolean h_found_line; gdouble v_x1, v_x2, v_y1, v_y2; gboolean v_found_line; gint width, height; /* We just try to find both right away, even though we can only * expect to find one of them. */ h_found_line = follow_line(surface, x, y, x_dir, 0, line_width, line_length, line_max_length, &h_x1, &h_y1, &h_x2, &h_y2); v_found_line = follow_line(surface, x, y, 0, y_dir, line_width, line_length, line_max_length, &v_x1, &v_y1, &v_x2, &v_y2); if (!(h_found_line || v_found_line)) return FALSE; if (!h_found_line) { if (y_dir < 0) h_found_line = follow_line(surface, v_x1, v_y1, x_dir, 0, line_width, line_length, line_max_length, &h_x1, &h_y1, &h_x2, &h_y2); else h_found_line = follow_line(surface, v_x2, v_y2, x_dir, 0, line_width, line_length, line_max_length, &h_x1, &h_y1, &h_x2, &h_y2); } if (!v_found_line) { if (x_dir < 0) v_found_line = follow_line(surface, h_x1, h_y1, 0, y_dir, line_width, line_length, line_max_length, &v_x1, &v_y1, &v_x2, &v_y2); else v_found_line = follow_line(surface, h_x2, h_y2, 0, y_dir, line_width, line_length, line_max_length, &v_x1, &v_y1, &v_x2, &v_y2); } if (!v_found_line || !h_found_line) return FALSE; /* Check that two of the endpoints are close together. */ if ((DIST(h_x1, h_y1, v_x1, v_y1) > line_width * 3) && (DIST(h_x1, h_y1, v_x2, v_y2) > line_width * 3) && (DIST(h_x2, h_y2, v_x1, v_y1) > line_width * 3) && (DIST(h_x2, h_y2, v_x2, v_y2) > line_width * 3)) return FALSE; calc_intersection(h_x1, h_y1, h_x2, h_y2, v_x1, v_y1, v_x2, v_y2, x_result, y_result); /* Check that the resulting position is not on the border of the image. */ width = cairo_image_surface_get_width (surface); height = cairo_image_surface_get_height (surface); if (*x_result - 3*line_width <= 0) return FALSE; if (*x_result + 3*line_width >= width) return FALSE; if (*y_result - 3*line_width <= 0) return FALSE; if (*y_result + 3*line_width >= height) return FALSE; return TRUE; } static gboolean real_find_corner_marker(cairo_surface_t *surface, gint x_start, gint y_start, gint x_dir, gint y_dir, gint search_distance, gint line_width, gint line_length, gint line_max_length, gdouble *x_result, gdouble *y_result) { gint x, y; gint distance = 0; gint search; gboolean found = FALSE; gint coverage = 0; while (!found && (distance < search_distance)) { distance += line_length / 4; /* Try searching from the top/bottom. */ coverage = 0; x = x_start + (x_dir * line_width) / 2 + x_dir * distance; y = y_start + (y_dir * line_width) / 2; for (search = 0; search < distance; search++) { gint old_coverage = coverage; y += y_dir; coverage = count_black_pixel(surface, x - line_width / 2, y - line_width / 2, line_width, line_width); if ((old_coverage > (line_width * line_width) * LINE_COVERAGE) && (old_coverage > coverage)) { if (test_corner_marker(surface, x, y, -x_dir, -y_dir, line_width, line_length, line_max_length, x_result, y_result)) return TRUE; } } /* Try searching from the left/right. */ coverage = 0; x = x_start + x_dir * line_width / 2; y = y_start + y_dir * line_width / 2 + y_dir * distance; for (search = 0; search < distance; search++) { gint old_coverage = coverage; x += x_dir; coverage = count_black_pixel(surface, x - line_width / 2, y - line_width / 2, line_width, line_width); if ((old_coverage > (line_width * line_width) * LINE_COVERAGE) && (old_coverage > coverage)) { if (test_corner_marker(surface, x, y, -x_dir, -y_dir, line_width, line_length, line_max_length, x_result, y_result)) return TRUE; } } } return FALSE; } /* Find corner marker */ gboolean find_corner_marker(cairo_surface_t *surface, cairo_matrix_t *matrix, gint corner, gdouble *marker_x, gdouble *marker_y) { gint width, height; gint line_width; gint line_length; gint line_max_length; gint dx, dy; gint start_x, start_y; gint search_distance; line_width = transform_distance_to_pixel(matrix, sdaps_line_width); line_length = transform_distance_to_pixel(matrix, sdaps_line_min_length); line_max_length = transform_distance_to_pixel(matrix, sdaps_line_max_length); search_distance = transform_distance_to_pixel(matrix, sdaps_corner_mark_search_distance); width = cairo_image_surface_get_width (surface); height = cairo_image_surface_get_height (surface); switch (corner) { case 1: dx = 1; dy = 1; start_x = 0; start_y = 0; break; case 2: dx = -1; dy = 1; start_x = width; start_y = 0; break; case 3: dx = -1; dy = -1; start_x = width; start_y = height; break; case 4: dx = 1; dy = -1; start_x = 0; start_y = height; break; default: g_assert_not_reached(); } return real_find_corner_marker(surface, start_x, start_y, dx, dy, search_distance, line_width, line_length, line_max_length, marker_x, marker_y); } cairo_matrix_t* calculate_correction_matrix_masked(cairo_surface_t *surface, cairo_surface_t *mask, cairo_matrix_t *matrix, gdouble mm_x, gdouble mm_y, gdouble *covered) { gdouble tmp_x, tmp_y; gint px_x, px_y, px_width, px_height; cairo_matrix_t inverse; cairo_matrix_t *result = NULL; gint test_dist; gint x_offset, y_offset; gint x_cov; gint y_cov; gint coverage = 0; inverse = *matrix; cairo_matrix_invert(&inverse); tmp_x = mm_x; tmp_y = mm_y; cairo_matrix_transform_point(matrix, &tmp_x, &tmp_y); px_x = tmp_x; px_y = tmp_y; /* Shut up the compiler. */ x_cov = px_x; y_cov = px_y; px_width = cairo_image_surface_get_width(mask); px_height = cairo_image_surface_get_height(mask); test_dist = MIN(px_width, px_height) / 2; /* Top */ for (x_offset = -test_dist; x_offset <= test_dist; x_offset++) { for (y_offset = -test_dist; y_offset <= test_dist; y_offset++) { gint new_cov; new_cov = count_black_pixel_masked(surface, mask, px_x + x_offset, px_y + y_offset); if (coverage < new_cov) { coverage = new_cov; x_cov = px_x + x_offset; y_cov = px_y + y_offset; } } } tmp_x = x_cov; tmp_y = y_cov; cairo_matrix_transform_point(&inverse, &tmp_x, &tmp_y); result = g_new(cairo_matrix_t, 1); cairo_matrix_init_identity(result); /* Just a translation */ result->x0 = tmp_x - mm_x; result->y0 = tmp_y - mm_y; *covered = coverage / (float) count_black_pixel(mask, 0, 0, px_width, px_height); return result; } gboolean find_box_corners(cairo_surface_t *surface, cairo_matrix_t *matrix, gdouble mm_x, gdouble mm_y, gdouble mm_width, gdouble mm_height, gdouble *mm_x1, gdouble *mm_y1, gdouble *mm_x2, gdouble *mm_y2, gdouble *mm_x3, gdouble *mm_y3, gdouble *mm_x4, gdouble *mm_y4) { cairo_matrix_t inverse; gdouble px_x1, px_y1, px_x2, px_y2, px_x3, px_y3, px_x4, px_y4; gdouble px_width, px_height; gint line_width; gint line_length; gint line_max_length; gint search_distance; line_width = transform_distance_to_pixel(matrix, sdaps_line_width); inverse = *matrix; cairo_matrix_invert(&inverse); /* Assume that the image is loaded rotated and pixel with/height is positive. */ px_x1 = mm_x; px_y1 = mm_y; px_x2 = mm_x + mm_width; px_y2 = mm_y; px_x3 = mm_x + mm_width; px_y3 = mm_y + mm_height; px_x4 = mm_x; px_y4 = mm_y + mm_height; px_width = mm_width; px_height = mm_height; cairo_matrix_transform_point(matrix, &px_x1, &px_y1); cairo_matrix_transform_point(matrix, &px_x2, &px_y2); cairo_matrix_transform_point(matrix, &px_x3, &px_y3); cairo_matrix_transform_point(matrix, &px_x4, &px_y4); cairo_matrix_transform_distance(matrix, &px_width, &px_height); line_length = MIN(10*line_width, MIN(px_width, px_height)) - line_width; line_max_length = MAX(10*line_width, MAX(px_width, px_height)) + 5*line_width; search_distance = line_length; /* We have the corner pixel positions, now try to find them. */ if (!real_find_corner_marker(surface, px_x1 - 4*line_width, px_y1 - 4*line_width, 1, 1, search_distance, line_width, line_length, line_max_length, &px_x1, &px_y1)) return FALSE; if (!real_find_corner_marker(surface, px_x2 + 4*line_width, px_y2 - 4*line_width, -1, 1, search_distance, line_width, line_length, line_max_length, &px_x2, &px_y2)) return FALSE; if (!real_find_corner_marker(surface, px_x3 + 4*line_width, px_y3 + 4*line_width, -1, -1, search_distance, line_width, line_length, line_max_length, &px_x3, &px_y3)) return FALSE; if (!real_find_corner_marker(surface, px_x4 - 4*line_width, px_y4 + 4*line_width, 1, -1, search_distance, line_width, line_length, line_max_length, &px_x4, &px_y4)) return FALSE; /* Found the corners, convert them back and return. */ *mm_x1 = px_x1; *mm_y1 = px_y1; *mm_x2 = px_x2; *mm_y2 = px_y2; *mm_x3 = px_x3; *mm_y3 = px_y3; *mm_x4 = px_x4; *mm_y4 = px_y4; cairo_matrix_transform_point(&inverse, mm_x1, mm_y1); cairo_matrix_transform_point(&inverse, mm_x2, mm_y2); cairo_matrix_transform_point(&inverse, mm_x3, mm_y3); cairo_matrix_transform_point(&inverse, mm_x4, mm_y4); return TRUE; } float get_coverage(cairo_surface_t *surface, cairo_matrix_t *matrix, gdouble mm_x, gdouble mm_y, gdouble mm_width, gdouble mm_height) { gint x, y, width, height; gdouble tmp_x, tmp_y; gint black, all; /* Transform to pixel. */ tmp_x = mm_x; tmp_y = mm_y; cairo_matrix_transform_point(matrix, &tmp_x, &tmp_y); x = tmp_x; y = tmp_y; tmp_x = mm_width; tmp_y = mm_height; cairo_matrix_transform_distance(matrix, &tmp_x, &tmp_y); width = tmp_x; height = tmp_y; black = count_black_pixel(surface, x, y, width, height); all = width * height; if (sdaps_create_debug_surface) { cairo_surface_t *surf = debug_surface_create(x, y, width, height, 0, 0, 0, 0); cairo_t *cr = cairo_create(surf); cairo_set_source_rgba(cr, 1, 0, 0, 0.5); cairo_paint(cr); cairo_destroy(cr); cairo_surface_flush(surf); } return black / (double) all; } float get_masked_coverage(cairo_surface_t *surface, cairo_surface_t *mask, gint x, gint y) { gint width, height; gint black, all; width = cairo_image_surface_get_width(mask); height = cairo_image_surface_get_height(mask); all = count_black_pixel(mask, 0, 0, width, height); black = count_black_pixel_masked(surface, mask, x, y); if (sdaps_create_debug_surface) { cairo_surface_t *surf = debug_surface_create(x, y, width, height, 0, 0, 0, 0); cairo_t *cr = cairo_create(surf); cairo_set_source_rgba(cr, 1, 0, 0, 0.5); cairo_mask_surface(cr, mask, 0, 0); cairo_destroy(cr); cairo_surface_flush(surf); } return black / (double) all; } /* First removes the number of lines, and then calculates the coverage of what * is left. */ gdouble get_masked_coverage_without_lines(cairo_surface_t *surface, cairo_surface_t *mask, gint x, gint y, gdouble line_width, gint line_count) { cairo_surface_t *tmp_surface; cairo_surface_t *debug_surf; gint width, height; gdouble result; gint i, all; width = cairo_image_surface_get_width(mask); height = cairo_image_surface_get_height(mask); all = count_black_pixel(mask, 0, 0, width, height); tmp_surface = surface_copy_masked(surface, mask, x, y); debug_surf = debug_surface_create(x, y, width, height, 0, 0, 0, 0); if (debug_surf) { cairo_t *cr; cr = cairo_create(debug_surf); cairo_set_source_rgba(cr, 0, 0, 1, 0.5); cairo_mask_surface(cr, mask, 0, 0); cairo_destroy(cr); cairo_surface_flush(debug_surf); } #if 0 /* Something like this could be used to filter the image first. * Obviously, for that to work, the size of the surface needs to be * adjusted accordingly. */ kfill_modified(tmp_surface, 5); cr = cairo_create(tmp_surface); cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); cairo_rectangle(cr, 0, 0, width+4, height+4); cairo_rectangle(cr, 2, 2, width, height); cairo_set_source_rgba(cr, 0, 0, 0, 0); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); cairo_fill(cr); cairo_destroy(cr); cairo_surface_flush(tmp_surface); #endif /* Remove the requested number of lines. */ for (i = 0; i < line_count; i++) remove_maximum_line(tmp_surface, debug_surf, line_width); result = count_black_pixel(tmp_surface, 0, 0, width, height) / (gdouble) all; cairo_surface_destroy(tmp_surface); return result; } guint get_masked_white_area_count(cairo_surface_t *surface, cairo_surface_t *mask, gint x, gint y, gdouble min_size, gdouble max_size, gdouble *filled_area) { cairo_surface_t *tmp_surface; cairo_surface_t *backup_surface; cairo_surface_t *debug_surf; cairo_t *backup_cr; gint width, height; guint result = 0; guint min_size_px; guint max_size_px; guint all; width = cairo_image_surface_get_width(mask); height = cairo_image_surface_get_height(mask); all = count_black_pixel(mask, 0, 0, width, height); min_size_px = all * min_size; max_size_px = all * max_size; tmp_surface = surface_inverted_copy_masked(surface, mask, x, y); /* Debug images */ debug_surf = debug_surface_create(x, y, width, height, 0, 0, 0, 0); if (debug_surf != NULL) { cairo_t *debug_cr; backup_surface = surface_copy(tmp_surface); backup_cr = cairo_create(backup_surface); cairo_set_operator(backup_cr, CAIRO_OPERATOR_SOURCE); debug_cr = cairo_create(debug_surf); cairo_set_source_rgba(debug_cr, 0, 0, 1, 0.5); cairo_mask_surface(debug_cr, tmp_surface, 0, 0); cairo_destroy(debug_cr); cairo_surface_flush(debug_surf); } *filled_area = 0; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { if (debug_surf != NULL) { cairo_set_source_surface(backup_cr, tmp_surface, 0, 0); cairo_paint(backup_cr); } guint area = flood_fill(tmp_surface, NULL, x, y, 1); if ((area >= min_size_px) && (area <= max_size_px)) { result += 1; *filled_area += area / ((gdouble) all); /* Flood fill again, this time also mark the area on the debug surface. */ if (debug_surf) flood_fill(backup_surface, debug_surf, x, y, 1); } } } if (debug_surf != NULL) { cairo_surface_destroy(backup_surface); cairo_destroy(backup_cr); } cairo_surface_destroy(tmp_surface); return result; } sdaps-1.9.8/sdaps/image/image.h0000644000175000000660000000563413346275473017054 0ustar benjaminlock00000000000000/* SDAPS * Copyright (C) 2008 Benjamin Berg * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include /* Some of the more important Magic Values */ extern gdouble sdaps_line_min_length; extern gdouble sdaps_line_max_length; extern gdouble sdaps_line_width; extern gdouble sdaps_corner_mark_search_distance; extern gdouble sdaps_line_coverage; extern gboolean sdaps_create_debug_surface; extern gint sdaps_debug_surface_ox; extern gint sdaps_debug_surface_oy; extern cairo_surface_t *sdaps_debug_surface; void disable_libtiff_warnings (void); cairo_surface_t* get_a1_from_tiff (const char *filename, gint page, gboolean rotated); gboolean write_a1_to_tiff (const char *filename, cairo_surface_t *surf); cairo_surface_t* get_rgb24_from_tiff (const char *filename, gint page, gboolean rotated); gint get_tiff_page_count (const char *filename); gboolean get_tiff_resolution (const char *filename, gint page, gdouble *xresolution, gdouble *yresolution); gboolean check_tiff_monochrome (const char *filename); gboolean find_corner_marker(cairo_surface_t *surface, cairo_matrix_t *matrix, gint corner, gdouble *marker_x, gdouble *marker_y); cairo_matrix_t* calculate_matrix(cairo_surface_t *surface, cairo_matrix_t *matrix, gdouble mm_x, gdouble mm_y, gdouble mm_width, gdouble mm_height); cairo_matrix_t* calculate_correction_matrix_masked(cairo_surface_t *surface, cairo_surface_t *mask, cairo_matrix_t *matrix, gdouble mm_x, gdouble mm_y, gdouble *covered); gboolean find_box_corners(cairo_surface_t *surface, cairo_matrix_t *matrix, gdouble mm_x, gdouble mm_y, gdouble mm_width, gdouble mm_height, gdouble *mm_x1, gdouble *mm_y1, gdouble *mm_x2, gdouble *mm_y2, gdouble *mm_x3, gdouble *mm_y3, gdouble *mm_x4, gdouble *mm_y4); float get_coverage(cairo_surface_t *surface, cairo_matrix_t *matrix, gdouble mm_x, gdouble mm_y, gdouble mm_width, gdouble mm_height); float get_masked_coverage(cairo_surface_t *surface, cairo_surface_t *mask, gint x, gint y); gdouble get_masked_coverage_without_lines(cairo_surface_t *surface, cairo_surface_t *mask, gint x, gint y, gdouble line_width, gint line_count); guint get_masked_white_area_count(cairo_surface_t *surface, cairo_surface_t *mask, gint x, gint y, gdouble min_size, gdouble max_size, gdouble *filled_area); sdaps-1.9.8/sdaps/image/surface.c0000644000175000000660000002303213346275473017405 0ustar benjaminlock00000000000000/* SDAPS * Copyright (C) 2012 Benjamin Berg * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "string.h" #include "surface.h" #define WORD_COUNT_BITS(x) (bitcount_table[(x) & 0xff] + bitcount_table[((x) >> 8) & 0xff] + bitcount_table[((x) >> 16) & 0xff] + bitcount_table[((x) >> 24) & 0xff]) static guint8 bitcount_table[256]; static gint bitcount_table_initialized = FALSE; static void ensure_bitcount_table(void) { if (G_UNLIKELY(!bitcount_table_initialized)) { int i; for (i = 0; i < 256; i++) { int j; bitcount_table[i] = 0; for (j = i; j; j = j >> 1) { bitcount_table[i] += j & 0x1; } } bitcount_table_initialized = TRUE; } } cairo_surface_t* surface_copy_partial(cairo_surface_t *surface, int x, int y, int width, int height) { cairo_surface_t *result; cairo_t *cr; result = cairo_image_surface_create(cairo_image_surface_get_format(surface), width, height); cr = cairo_create(result); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); /* In case the area is outside of the source image, fill with zeros. */ cairo_set_source_rgba(cr, 0, 0, 0, 0); cairo_paint(cr); cairo_set_source_surface(cr, surface, -x, -y); cairo_paint(cr); cairo_destroy(cr); cairo_surface_flush(result); return result; } cairo_surface_t* surface_copy(cairo_surface_t *surface) { int width, height; width = cairo_image_surface_get_width(surface); height = cairo_image_surface_get_height(surface); return surface_copy_partial(surface, 0, 0, width, height); } cairo_surface_t* surface_copy_masked(cairo_surface_t *surface, cairo_surface_t *mask, gint x, gint y) { gint width, height; gint word_width; cairo_surface_t *result; gint result_stride, mask_stride; guint32 *result_pixels, *mask_pixels; width = cairo_image_surface_get_width(mask); height = cairo_image_surface_get_height(mask); result = surface_copy_partial(surface, x, y, width, height); result_pixels = (guint32*) cairo_image_surface_get_data(result); result_stride = cairo_image_surface_get_stride(result); mask_pixels = (guint32*) cairo_image_surface_get_data(mask); mask_stride = cairo_image_surface_get_stride(mask); word_width = (width + 31) / 32; for (y = 0; y < height; y++) { for (x = 0; x < word_width; x++) { result_pixels[x + y*result_stride/4] &= mask_pixels[x + y*mask_stride/4]; } } cairo_surface_mark_dirty(result); return result; } cairo_surface_t* surface_inverted_copy_masked(cairo_surface_t *surface, cairo_surface_t *mask, gint x, gint y) { gint width, height; gint word_width; cairo_surface_t *result; gint result_stride, mask_stride; guint32 *result_pixels, *mask_pixels; width = cairo_image_surface_get_width(mask); height = cairo_image_surface_get_height(mask); result = surface_copy_partial(surface, x, y, width, height); result_pixels = (guint32*) cairo_image_surface_get_data(result); result_stride = cairo_image_surface_get_stride(result); mask_pixels = (guint32*) cairo_image_surface_get_data(mask); mask_stride = cairo_image_surface_get_stride(mask); word_width = (width + 31) / 32; for (y = 0; y < height; y++) { for (x = 0; x < word_width; x++) { result_pixels[x + y*result_stride/4] = ~result_pixels[x + y*result_stride/4] & mask_pixels[x + y*mask_stride/4]; } } cairo_surface_mark_dirty(result); return result; } /* Generic pixel routines */ void set_pixels_unchecked(guint32* pixels, guint32 stride, gint x, gint y, gint width, gint height, int value) { guint x_pos, y_pos; for (y_pos = y; y_pos < y + height; y_pos++) { for (x_pos = x; x_pos < x + width; x_pos++) { SET_PIXEL(pixels, stride, x_pos, y_pos, value); } } } void get_pbm(cairo_surface_t *surface, void **data, int *length) { int width, height; int s_stride; int d_stride; unsigned char* s_pixel; unsigned char* d_pixel; char *start; int x, y; *data = NULL; *length = 0; if (cairo_image_surface_get_format (surface) != CAIRO_FORMAT_A1) return; width = cairo_image_surface_get_width(surface); height = cairo_image_surface_get_height(surface); s_stride = cairo_image_surface_get_stride(surface); s_pixel = cairo_image_surface_get_data(surface); start = g_strdup_printf("P4\n%i %i\n", width, height); d_stride = (width + 7) / 8; *length = strlen(start) + height * d_stride; *data = g_malloc0(*length); strcpy(*data, start); d_pixel = *data + strlen(start); g_free(start); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { *(d_pixel + y*d_stride + x / 8) |= (GET_PIXEL(s_pixel, s_stride, x, y)) << (7 - x % 8); } } } gint count_black_pixel(cairo_surface_t *surface, gint x, gint y, gint width, gint height) { guint32 *pixels; guint stride; guint img_width, img_height; pixels = (guint32*) cairo_image_surface_get_data(surface); img_width = cairo_image_surface_get_width(surface); img_height = cairo_image_surface_get_height(surface); stride = cairo_image_surface_get_stride(surface); if (y < 0) { height += y; y = 0; } if (x < 0) { width += x; x = 0; } if ((width <= 0) || (height <= 0)) return 0; if (x + width > img_width) { width = img_width - x; } if (y + height > img_height) { height = img_height - y; } return count_black_pixel_unchecked(pixels, stride, x, y, width, height); } gint count_black_pixel_unchecked(guint32* pixels, guint32 stride, gint x, gint y, gint width, gint height) { guint y_pos; guint black_pixel = 0; ensure_bitcount_table(); for (y_pos = y; y_pos < y + height; y_pos++) { guint32 start_mask; guint32 end_mask; int start; int end; int pos; #if G_BYTE_ORDER == G_BIG_ENDIAN start_mask = (1 << (x & 0x1f)) - 1; end_mask = -(1 << ((x + width) & 0x1f)); #else start_mask = -(1 << (x & 0x1f)); end_mask = (1 << ((x + width) & 0x1f)) - 1; #endif start = x >> 5; end = (x + width) >> 5; if (start == end) { black_pixel += WORD_COUNT_BITS(pixels[start + y_pos * stride / 4] & start_mask & end_mask); } else { black_pixel += WORD_COUNT_BITS(pixels[start + y_pos * stride / 4] & start_mask); for (pos = start + 1; pos < end; pos++) { black_pixel += WORD_COUNT_BITS(pixels[pos + y_pos * stride / 4]); } black_pixel += WORD_COUNT_BITS(pixels[end + y_pos * stride / 4] & end_mask); } } return black_pixel; } gint count_black_pixel_masked(cairo_surface_t *surface, cairo_surface_t *mask, gint x, gint y) { guint32 *pixels; guint32 *mask_pixels; guint stride; guint mask_stride; gint width, height; guint img_width, img_height; width = cairo_image_surface_get_width(mask); height = cairo_image_surface_get_height(mask); mask_pixels = (guint32*) cairo_image_surface_get_data(mask); mask_stride = cairo_image_surface_get_stride(mask); pixels = (guint32*) cairo_image_surface_get_data(surface); img_width = cairo_image_surface_get_width(surface); img_height = cairo_image_surface_get_height(surface); stride = cairo_image_surface_get_stride(surface); /* Ignore if the mask is not completely in the image ... */ if (y < 0) { return 0; } if (x < 0) { return 0; } if ((width <= 0) || (height <= 0)) return 0; if (x + width > img_width) { return 0; } if (y + height > img_height) { return 0; } return count_black_pixel_masked_unchecked(pixels, stride, mask_pixels, mask_stride, x, y, width, height); } gint count_black_pixel_masked_unchecked(guint32* pixels, guint32 stride, guint32 *mask_pixels, guint32 mask_stride, gint x, gint y, gint width, gint height) { guint y_pos; guint black_pixel = 0; ensure_bitcount_table(); for (y_pos = 0; y_pos < height; y_pos++) { guint32 end_mask; guint32 curr_pixels; int end; int pos; #if G_BYTE_ORDER == G_BIG_ENDIAN end_mask = -(1 << (width & 0x1f)); #else end_mask = (1 << (width & 0x1f)) - 1; #endif end = width >> 5; for (pos = 0; pos <= end; pos++) { /* Note that a shift of 32 is not defined, it may also be 0. */ #if G_BYTE_ORDER == G_BIG_ENDIAN curr_pixels = pixels[(x / 32) + pos + (y_pos + y) * stride / 4] << (x % 32); curr_pixels |= pixels[((x + 31) / 32) + pos + (y_pos + y) * stride / 4] >> (32 - (x % 32)); #else curr_pixels = pixels[(x / 32) + pos + (y_pos + y) * stride / 4] >> (x % 32); curr_pixels |= pixels[((x + 31) / 32) + pos + (y_pos + y) * stride / 4] << (32 - (x % 32)); #endif curr_pixels &= mask_pixels[pos + y_pos * mask_stride / 4]; if (pos == end) curr_pixels &= end_mask; black_pixel += WORD_COUNT_BITS(curr_pixels); } } return black_pixel; } #if 0 /* This function is for debugging purposes. */ void a1_surface_write_to_png(cairo_surface_t* surface, gchar* filename) { guint img_width, img_height; cairo_surface_t *tmp_surface; cairo_t *cr; img_width = cairo_image_surface_get_width(surface); img_height = cairo_image_surface_get_height(surface); tmp_surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, img_width, img_height); cr = cairo_create(tmp_surface); cairo_set_source_rgb(cr, 1, 1, 1); cairo_paint(cr); cairo_set_source_rgb(cr, 0, 0, 0); cairo_mask_surface(cr, surface, 0, 0); cairo_surface_write_to_png(tmp_surface, filename); cairo_destroy(cr); cairo_surface_destroy(tmp_surface); } #endif sdaps-1.9.8/sdaps/image/surface.h0000644000175000000660000000747513346275473017427 0ustar benjaminlock00000000000000/* SDAPS * Copyright (C) 2012 Benjamin Berg * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #if G_BYTE_ORDER == G_BIG_ENDIAN #define SET_PIXEL(_pixels, _stride, _x, _y, _value) *(guint32*)((char*)(_pixels) + (_stride) * (_y) + (_x) / 32 * 4) = (*(guint32*)((char*)(_pixels) + (_stride) * (_y) + (_x) / 32 * 4) & (0xffffffff ^ (1 << (31 - (_x) % 32)))) | ((!!(_value)) << (31 - (_x) % 32)) #define GET_PIXEL(_pixels, _stride, _x, _y) (((*(guint32*)((char*)(_pixels) + (_stride) * (_y) + (_x) / 32 * 4)) >> (31 - (_x) % 32)) & 0x1) #define BARREL_VARS guint32* _barrel_curr_pos; guint _barrel_bits; guint32 _barrel_value_storage; #define BARREL_START_ROW(_row_ptr) _barrel_value_storage = 0; _barrel_bits = 0; _barrel_curr_pos = (guint32*)(_row_ptr); #define BARREL_STORE_BIT(_value) _barrel_bits++; _barrel_value_storage = (_value) | _barrel_value_storage << 1; if (_barrel_bits == 32) { *_barrel_curr_pos = _barrel_value_storage; _barrel_curr_pos++; _barrel_bits = 0; }; #define BARREL_FLUSH if (_barrel_bits > 0) { *_barrel_curr_pos = _barrel_value_storage << (32-_barrel_bits); _barrel_curr_pos++; _barrel_bits = 0; } #else #define SET_PIXEL(_pixels, _stride, _x, _y, _value) *(guint32*)((char*)(_pixels) + (_stride) * (_y) + (_x) / 32 * 4) = (*(guint32*)((char*)(_pixels) + (_stride) * (_y) + (_x) / 32 * 4) & (0xffffffff ^ (1 << ((_x) % 32)))) | ((!!(_value)) << ((_x) % 32)) #define GET_PIXEL(_pixels, _stride, _x, _y) (((*(guint32*)((char*)(_pixels) + (_stride) * (_y) + (_x) / 32 * 4)) >> ((_x) % 32)) & 0x1) #define BARREL_VARS guint32* _barrel_curr_pos; guint _barrel_bits; guint32 _barrel_value_storage; #define BARREL_START_ROW(_row_ptr) _barrel_value_storage = 0; _barrel_bits = 0; _barrel_curr_pos = (guint32*)(_row_ptr); #define BARREL_STORE_BIT(_value) _barrel_bits++; _barrel_value_storage = (_value) << 31 | _barrel_value_storage >> 1; if (_barrel_bits == 32) { *_barrel_curr_pos = _barrel_value_storage; _barrel_curr_pos++; _barrel_bits = 0; }; #define BARREL_FLUSH if (_barrel_bits > 0) { *_barrel_curr_pos = _barrel_value_storage >> (32-_barrel_bits); _barrel_curr_pos++; _barrel_bits = 0; } #endif cairo_surface_t* surface_copy_partial(cairo_surface_t *surface, int x, int y, int width, int height); cairo_surface_t* surface_copy(cairo_surface_t *surface); cairo_surface_t* surface_copy_masked(cairo_surface_t *surface, cairo_surface_t *mask, gint x, gint y); cairo_surface_t* surface_inverted_copy_masked(cairo_surface_t *surface, cairo_surface_t *mask, gint x, gint y); void get_pbm(cairo_surface_t *surface, void **data, int *length); #if 0 void a1_surface_write_to_png(cairo_surface_t* surface, gchar* filename); #endif gint count_black_pixel(cairo_surface_t *surface, gint x, gint y, gint width, gint height); gint count_black_pixel_masked(cairo_surface_t *surface, cairo_surface_t *mask, gint x, gint y); gint count_black_pixel_unchecked(guint32* pixels, guint32 stride, gint x, gint y, gint width, gint height); gint count_black_pixel_masked_unchecked(guint32* pixels, guint32 stride, guint32 *mask_pixels, guint32 mask_stride, gint x, gint y, gint width, gint height); void set_pixels_unchecked(guint32* pixels, guint32 stride, gint x, gint y, gint width, gint height, int value); sdaps-1.9.8/sdaps/image/transform.c0000644000175000000660000003454013346275473017776 0ustar benjaminlock00000000000000/* SDAPS * Copyright (C) 2012 Benjamin Berg * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "transform.h" #include "surface.h" #include #include /* The following is an adaption from gamera. It is a modified * kfill algorithm. * * The original code was released under the GPLv2 or any later version. * * The Gamera authors for the file are: * Copyright (C) 2001-2005 Ichiro Fujinaga, Michael Droettboom, Karl MacMillan * 2010 Christoph Dalitz, Oliver Christen * 2011-2012 Christoph Dalitz, David Kolanus * * The same algorithm is used in queXF for character recognition. */ void kfill_get_condition_variables(guint32 *pixels, guint stride, guint k, guint x, guint y, gint *n, gint *r, gint *c) { guint corner_pixel_count; guint ccs; guint pixel_count; guint pixel, last_px; guint _x, _y; corner_pixel_count = GET_PIXEL(pixels, stride, x, y); corner_pixel_count += GET_PIXEL(pixels, stride, x + k - 1, y); corner_pixel_count += GET_PIXEL(pixels, stride, x, y + k - 1); corner_pixel_count += GET_PIXEL(pixels, stride, x + k - 1, y + k - 1); /* Count border pixels and number of color changes when walking around * the border. */ ccs = 0; pixel_count = 0; /* The last pixel is also the "first". */ last_px = GET_PIXEL(pixels, stride, x, y + 1); _y = y; _x = x; for (; _x < x + k - 1; _x++) { pixel = GET_PIXEL(pixels, stride, _x, _y); if (last_px != pixel) ccs += 1; pixel_count += pixel; last_px = pixel; } for (; _y < y + k - 1; _y++) { pixel = GET_PIXEL(pixels, stride, _x, _y); if (last_px != pixel) ccs += 1; pixel_count += pixel; last_px = pixel; } for (; _x > x; _x--) { pixel = GET_PIXEL(pixels, stride, _x, _y); if (last_px != pixel) ccs += 1; pixel_count += pixel; last_px = pixel; } for (; _y > y; _y--) { pixel = GET_PIXEL(pixels, stride, _x, _y); if (last_px != pixel) ccs += 1; pixel_count += pixel; last_px = pixel; } *n = pixel_count; *r = corner_pixel_count; *c = ccs; } /* This implementation of kfill_modified works in place. */ void kfill_modified(cairo_surface_t* surface, gint k) { guint x, y; guint img_width, img_height; guint stride, tmp_stride; guint32 *pixels, *tmp_pixels; guint core_pixels; guint core_color; /* r: number of pixels in the neighborhood corners * n: number of pixels in the neighberhood * c: number of ccs in neighborhood */ gint r, n, c; cairo_surface_t *tmp_surface; tmp_surface = surface_copy(surface); img_width = cairo_image_surface_get_width(surface); img_height = cairo_image_surface_get_height(surface); pixels = (guint32*) cairo_image_surface_get_data(surface); stride = cairo_image_surface_get_stride(surface); tmp_pixels = (guint32*) cairo_image_surface_get_data(tmp_surface); tmp_stride = cairo_image_surface_get_stride(tmp_surface); for (y = 0; y < img_height - k; y++) { for (x = 0; x < img_width - k; x++) { core_pixels = count_black_pixel_unchecked(tmp_pixels, tmp_stride, x+1, y+1, k-2, k-2); kfill_get_condition_variables(tmp_pixels, tmp_stride, k, x, y, &n, &r, &c); /* more than half black or white? This would be the new core color. */ core_color = core_pixels * 2 >= (k-2)*(k-2); if (core_color) { n = ( 4*(k-1) ) - n; r = 4 - r; } if ((c <= 1) && ((n > 3*k - 4) || ((n == 3*k - 4) && (r == 2)))) { set_pixels_unchecked(pixels, stride, x+1, y+1, k-2, k-2, !core_color); } else { set_pixels_unchecked(pixels, stride, x+1, y+1, k-2, k-2, core_color); } } } } static void mark_pixel(cairo_surface_t *debug_surf, gint x, gint y) { cairo_t *cr; cr = cairo_create(debug_surf); cairo_set_source_rgba(cr, 1, 0, 0, 0.5); cairo_rectangle(cr, x-0.5, y-0.5, 1, 1); cairo_fill(cr); cairo_destroy(cr); } /* XXX: This needs rather a lot of stack space ... * TODO: Rewrite in a saner and faster way. * Returns the size of the filled area. */ guint flood_fill(cairo_surface_t *surface, cairo_surface_t *debug_surf, gint x, gint y, gint orig_color) { guint img_width, img_height; guint stride; guint32 *pixels; guint result; img_width = cairo_image_surface_get_width(surface); img_height = cairo_image_surface_get_height(surface); pixels = (guint32*) cairo_image_surface_get_data(surface); stride = cairo_image_surface_get_stride(surface); if (x < 0) return 0; if (y < 0) return 0; if (x >= img_width) return 0; if (y >= img_height) return 0; if (GET_PIXEL(pixels, stride, x, y) != orig_color) return 0; /* Swap pixel value. */ SET_PIXEL(pixels, stride, x, y, !orig_color); result = 1; result += flood_fill(surface, debug_surf, x+1, y, orig_color); result += flood_fill(surface, debug_surf, x, y+1, orig_color); result += flood_fill(surface, debug_surf, x-1, y, orig_color); result += flood_fill(surface, debug_surf, x, y-1, orig_color); if (debug_surf != NULL) mark_pixel(debug_surf, x, y); return result; } /************************************************* * Hough transformation! *************************************************/ typedef struct { guint32 *data; guint angle_bins; guint distance_bins; guint max_distance; gdouble *cos_table; gdouble *sin_table; } hough_data; /* Adds a point to the hough transformation. A (gaussion) filter is applied * at the same time. * I guess this is slightly less efficient than filtering it later, but it * means we do not require a larger result space for filtering. */ void hough_add_point(hough_data *hough, guint x, guint y, guint filter_width, guint *filter_coff) { guint angle_step; gdouble r; gint r_bin, filt_bin; gint i; for (angle_step = 0; angle_step < hough->angle_bins; angle_step++) { r = x * hough->cos_table[angle_step] + y * hough->sin_table[angle_step]; /* Only add if r is larger than zero */ r_bin = (int)round(hough->distance_bins * r / hough->max_distance); for (i = 0; i < filter_width; i++) { filt_bin = r_bin + i - filter_width / 2; if ((filt_bin >= 0) && (filt_bin < hough->distance_bins)) { hough->data[angle_step*hough->distance_bins + filt_bin] += filter_coff[i]; } } } } static void hough_create_lut(hough_data *hough) { guint angle_step; gdouble angle; hough->cos_table = g_new(gdouble, hough->angle_bins); hough->sin_table = g_new(gdouble, hough->angle_bins); for (angle_step = 0; angle_step < hough->angle_bins; angle_step++) { angle = (2*G_PI * angle_step) / hough->angle_bins; hough->cos_table[angle_step] = cos(angle); hough->sin_table[angle_step] = sin(angle); } } guint get_gaussion(gdouble sigma, guint **filter_coff) { gint filt_length; gint center; gint i; g_assert(filter_coff != NULL); /* We just multiply the coefficients with 10, and we simply evaluate * the exponential function. */ /* Simply use two sigma for the filter width. */ center = (gint)ceil(sigma * 2); filt_length = ((gint)ceil(sigma * 2)) * 2 + 1; *filter_coff = g_new(guint, filt_length); for (i = 0; i < center; i++) { (*filter_coff)[i] = floor(10*exp(-(gdouble)((i - center)*(i - center)) / pow(sigma, 2) / 2.0)); (*filter_coff)[filt_length - i - 1] = (*filter_coff)[i]; } (*filter_coff)[center] = 10; return filt_length; } /* Hough transforms the image. * * */ hough_data* hough_transform(cairo_surface_t *surface, guint angle_bins, guint distance_bins, gdouble sigma_px) { guint img_width, img_height; guint stride; guint x, y; guint32 *pixels; guint filter_length; guint *filter; hough_data *result = g_malloc(sizeof(hough_data)); result->data = NULL; result->cos_table = NULL; result->sin_table = NULL; img_width = cairo_image_surface_get_width(surface); img_height = cairo_image_surface_get_height(surface); result->angle_bins = angle_bins; result->distance_bins = distance_bins; result->max_distance = (guint) sqrt(img_width*img_width + img_height*img_height); result->data = g_malloc0(sizeof(*result->data) * result->angle_bins*result->distance_bins); hough_create_lut(result); pixels = (guint32*) cairo_image_surface_get_data(surface); stride = cairo_image_surface_get_stride(surface); filter_length = get_gaussion(sigma_px * result->distance_bins / result->max_distance, &filter); for (y = 0; y < img_height; y++) { for (x = 0; x < img_width; x++) { if (GET_PIXEL(pixels, stride, x, y)) hough_add_point(result, x, y, filter_length, filter); } } g_free(filter); return result; } void hough_data_free(hough_data *data) { g_free(data->data); g_free(data->cos_table); g_free(data->sin_table); g_free(data); } static void remove_line(cairo_surface_t *surface, gdouble width, gdouble r_max, gdouble phi_max, gboolean debug) { guint img_width, img_height; cairo_t *cr; img_width = cairo_image_surface_get_width(surface); img_height = cairo_image_surface_get_height(surface); cr = cairo_create(surface); cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); if (!debug) { cairo_set_source_rgba(cr, 0, 0, 0, 0); } else { cairo_set_source_rgba(cr, 1, 0, 0, 0.5); } cairo_set_line_width(cr, width); if (sin(phi_max) > 0.1) { cairo_move_to(cr, 0, r_max / sin(phi_max)); cairo_line_to(cr, img_width, (r_max - img_width * cos(phi_max)) / sin(phi_max)); } else { cairo_move_to(cr, r_max / cos(phi_max), 0); cairo_line_to(cr, (r_max - img_height * sin(phi_max)) / cos(phi_max), img_height); } cairo_stroke(cr); cairo_destroy(cr); } void remove_maximum_line(cairo_surface_t *surface, cairo_surface_t *debug_surf, gdouble width) { int r, phi; gdouble r_max, phi_max, maximum; hough_data *hough = hough_transform(surface, 60, 30, width / 2.0); /* Shut up the compiler*/ r_max = 0; phi_max = 0; maximum = -1; /* Find global maximum. */ for (phi = 0; phi < hough->angle_bins; phi++) { for (r = 0; r < hough->distance_bins; r++) { guint32 *cur = &hough->data[phi * hough->distance_bins + r]; if (*cur > maximum) { maximum = *cur; r_max = r / (gdouble) hough->distance_bins * hough->max_distance; phi_max = phi / (gdouble) hough->angle_bins * G_PI*2; } } } remove_line(surface, width, r_max, phi_max, FALSE); if (debug_surf != NULL) remove_line(debug_surf, width, r_max, phi_max, TRUE); hough_data_free(hough); cairo_surface_flush(surface); } #if 0 /* The following is an adaption from the Animal imaging library. * The library was written by Ricardo Fabbri (2011) and is licensed under the * GPLv2 or any later version there. * The same algorithm is used in queXF for character recognition. */ /* Offsets to the neighbors of a pixel. */ static int n8[8][2] = { { 0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, { 0, -1}, { 1, -1}, { 1, 0}, { 1, 1} }; /* This function tells the number N of regions that would exist if the pixel P(r,c) where changed from FG to BG. It returns 2*N, that is, the number of pixel transitions in the neighbourhood. */ static int crossing_index_np(guint32 *pixels, int stride, int x, int y) { guint n=0, idx; guint current, next; /* The last one (so we get the crossing from last to first pixel). */ current = GET_PIXEL(pixels, stride, x + n8[7][0], y + n8[7][1]); for (idx = 0; idx < 8; idx++) { next = GET_PIXEL(pixels, stride, x + n8[idx][0], y + n8[idx][1]); if (next != current) n++; current = next; } return n; } int nh8count_np(guint32 *pixels, int stride, int x, int y, int val) { guint i, n=0; for (i=0; i < 8; i++) if (GET_PIXEL(pixels, stride, x + n8[i][1], y + n8[i][0]) == val) n++; return n; } /* In place Zhang-Suen thinning. The algorithm leaves a 1px border untouched. */ void thinzs_np(cairo_surface_t *surface) { gboolean modified; guint x, y, n; guint img_width, img_height; guint stride, tmp_stride; guint32 *pixels, *tmp_pixels; guint pixel; guint FG=1, BG=0; cairo_surface_t *tmp_surface; tmp_surface = surface_copy(surface); img_width = cairo_image_surface_get_width(surface); img_height = cairo_image_surface_get_height(surface); pixels = (guint32*) cairo_image_surface_get_data(surface); stride = cairo_image_surface_get_stride(surface); tmp_pixels = (guint32*) cairo_image_surface_get_data(tmp_surface); tmp_stride = cairo_image_surface_get_stride(tmp_surface); do { modified = FALSE; for (y=1; y < img_height-1; y++) for (x=1; x < img_width-1; x++) { pixel = GET_PIXEL(pixels, stride, x, y); SET_PIXEL(tmp_pixels, tmp_stride, x, y, pixel); if (pixel == FG) { n = nh8count_np(pixels, stride, x, y, FG); if ( n >= 2 && n <= 6 && crossing_index_np(pixels, stride, x, y) == 2) { if((GET_PIXEL(pixels, stride, x, y-1) == BG || GET_PIXEL(pixels, stride, x+1, y) == BG || GET_PIXEL(pixels, stride, x, y+1) == BG) && (GET_PIXEL(pixels, stride, x, y-1) == BG || GET_PIXEL(pixels, stride, x, y+1) == BG || GET_PIXEL(pixels, stride, x-1, y) == BG)) { SET_PIXEL(tmp_pixels, tmp_stride, x, y, BG); modified = TRUE; } } } } for (y=1; y < img_height-1; y++) for (x=1; x < img_width-1; x++) { pixel = GET_PIXEL(tmp_pixels, tmp_stride, x, y); SET_PIXEL(pixels, stride, x, y, pixel); if (pixel == FG) { n = nh8count_np(tmp_pixels, tmp_stride, x, y, FG); if ( n>=2 && n<=6 && crossing_index_np(tmp_pixels, tmp_stride, x, y) == 2) { if((GET_PIXEL(pixels, stride, x+1, y) == BG || GET_PIXEL(pixels, stride, x-1, y) == BG || GET_PIXEL(pixels, stride, x, y-1) == BG) && (GET_PIXEL(pixels, stride, x, y-1) == BG || GET_PIXEL(pixels, stride, x-1, y) == BG || GET_PIXEL(pixels, stride, x, y+1) == BG)) { SET_PIXEL(pixels, stride, x, y, BG); modified = TRUE; } } } } } while (modified); cairo_surface_destroy(tmp_surface); cairo_surface_mark_dirty(surface); } #endif sdaps-1.9.8/sdaps/image/transform.h0000644000175000000660000000211713346275473017776 0ustar benjaminlock00000000000000/* SDAPS * Copyright (C) 2012 Benjamin Berg * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #if 0 void thinzs_np(cairo_surface_t *surface); #endif void kfill_modified(cairo_surface_t* surface, gint k); guint flood_fill(cairo_surface_t *surface, cairo_surface_t *debug_surf, gint x, gint y, gint orig_color); void remove_maximum_line(cairo_surface_t *surface, cairo_surface_t *debug_surf, gdouble width); sdaps-1.9.8/sdaps/image/wrap_image.c0000644000175000000660000003574113575707425020103 0ustar benjaminlock00000000000000/* SDAPS * Copyright (C) 2008 Christoph Simon * Copyright (C) 2008 Benjamin Berg * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "image.h" #include "transform.h" #include "surface.h" #include #include #include static PyObject *wrap_get_a1_from_tiff(PyObject *self, PyObject *args); static PyObject *wrap_write_a1_to_tiff(PyObject *self, PyObject *args); static PyObject *wrap_get_rgb24_from_tiff(PyObject *self, PyObject *args); static PyObject *wrap_find_corner_marker(PyObject *self, PyObject *args); static PyObject *wrap_calculate_correction_matrix_masked(PyObject *self, PyObject *args); static PyObject *wrap_find_box_corners(PyObject *self, PyObject *args); static PyObject *wrap_get_coverage(PyObject *self, PyObject *args); static PyObject *wrap_get_masked_coverage(PyObject *self, PyObject *args); static PyObject *wrap_get_masked_coverage_without_lines(PyObject *self, PyObject *args); static PyObject *wrap_get_masked_white_area_count(PyObject *self, PyObject *args); static PyObject *wrap_get_pbm(PyObject *self, PyObject *args); static PyObject *sdaps_set_magic_values(PyObject *self, PyObject *args); static PyObject *enable_debug_surface_creation(PyObject *self, PyObject *args); static PyObject *get_debug_surface(PyObject *self, PyObject *args); static PyObject *wrap_get_tiff_page_count(PyObject *self, PyObject *args); static PyObject *wrap_get_tiff_resolution(PyObject *self, PyObject *args); static PyObject *wrap_check_tiff_monochrome(PyObject *self, PyObject *args); static PyObject *wrap_kfill_modified(PyObject *self, PyObject *args); static PyMethodDef image_methods[] = { {"get_a1_from_tiff", wrap_get_a1_from_tiff, METH_VARARGS, "Creates a cairo A1 surface from a monochrome tiff file."}, {"write_a1_to_tiff", wrap_write_a1_to_tiff, METH_VARARGS, "Appends a new page to an existing tiff file or create a new tiff file containing the pixel data from the surface."}, {"get_rgb24_from_tiff", wrap_get_rgb24_from_tiff, METH_VARARGS, "Creates a cairo RGB24 surface from a (monochrome) tiff file."}, {"get_tiff_page_count", wrap_get_tiff_page_count, METH_VARARGS, "Returns the number of pages a multipage tiff contains."}, {"get_tiff_resolution", wrap_get_tiff_resolution, METH_VARARGS, "Retrieves the resolution from the given page of the tiff file (in dots per mm)."}, {"check_tiff_monochrome", wrap_check_tiff_monochrome, METH_VARARGS, "Check whether all pages of the tiff are monochrome."}, {"find_corner_marker", wrap_find_corner_marker, METH_VARARGS, "Searches for a corner marker. The third parameter should be an integer specifying the corner (1: top left, 2: top right, 3: bottom right, 4: bottom left."}, {"calculate_correction_matrix_masked", wrap_calculate_correction_matrix_masked, METH_VARARGS, "Calculates a corrected transformation matrix for the mask at the given the top left corner."}, {"find_box_corners", wrap_find_box_corners, METH_VARARGS, "Tries to find the actuall corners of a box in the milimeter space."}, {"get_coverage", wrap_get_coverage, METH_VARARGS, "Calculates the black coverage in the given area."}, {"get_masked_coverage", wrap_get_masked_coverage, METH_VARARGS, "Calculates the black coverage in the given mask."}, {"get_masked_coverage_without_lines", wrap_get_masked_coverage_without_lines, METH_VARARGS, "First removes the number of requested lines with the specified stroke width using a hough transformation. Then calculates the coverage. Works on the masked area."}, {"get_masked_white_area_count", wrap_get_masked_white_area_count, METH_VARARGS, "Returns the number and overall size of white areas that are larger than the given percentage of the overall size. Works on the masked area."}, {"get_pbm", wrap_get_pbm, METH_VARARGS, "Returns a byte string that contains a binary PBM data representation of the cairo A1 surface."}, {"set_magic_values", sdaps_set_magic_values, METH_VARARGS, "Sets some magic values for recognition."}, {"enable_debug_surface_creation", enable_debug_surface_creation, METH_VARARGS, "Sets whether debug images should be created."}, {"get_debug_surface", get_debug_surface, METH_VARARGS, "Returns the last created debug surface. Call immediately after a function that may create such a surface."}, {"kfill_modified", wrap_kfill_modified, METH_VARARGS, "Run the modified KFill algorithm over the given A1 surface."}, {NULL, NULL, 0, NULL} /* Sentinel */ }; static struct PyModuleDef image_module = { PyModuleDef_HEAD_INIT, "image", NULL, 0, image_methods, 0, /* m_reload */ 0, /* m_traverse */ 0, /* m_clear */ 0, /* m_free */ }; PyMODINIT_FUNC PyInit_image(void) { PyObject *m; m = PyModule_Create(&image_module); if (m == NULL) return NULL; if (import_cairo() < 0) return NULL; /* supress warnings from libtiff. */ disable_libtiff_warnings (); return m; } static PyObject * wrap_get_a1_from_tiff(PyObject *self, PyObject *args) { cairo_surface_t *surface; const char *filename = NULL; gboolean rotated; gint page; if (!PyArg_ParseTuple(args, "sii", &filename, &page, &rotated)) return NULL; surface = get_a1_from_tiff(filename, page, rotated); if (surface) { return PycairoSurface_FromSurface(surface, NULL); } else { PyErr_SetString(PyExc_AssertionError, "The image surface could not be created! Broken or non 1bit tiff file?"); return NULL; } } static PyObject * wrap_write_a1_to_tiff(PyObject *self, PyObject *args) { PycairoSurface *py_surface; const char *filename = NULL; if (!PyArg_ParseTuple(args, "sO!", &filename, &PycairoImageSurface_Type, &py_surface)) return NULL; if (!write_a1_to_tiff(filename, py_surface->surface)) { PyErr_SetString(PyExc_AssertionError, "Error writing new page to TIFF file (append/create)!"); return NULL; } Py_INCREF(Py_None); return Py_None; } static PyObject * wrap_get_rgb24_from_tiff(PyObject *self, PyObject *args) { cairo_surface_t *surface; const char *filename = NULL; gboolean rotated; gint page; if (!PyArg_ParseTuple(args, "sii", &filename, &page, &rotated)) return NULL; surface = get_rgb24_from_tiff(filename, page, rotated); if (surface) { return PycairoSurface_FromSurface(surface, NULL); } else { PyErr_SetString(PyExc_AssertionError, "The image surface could not be created! Broken or non 1bit tiff file?"); return NULL; } } static PyObject * wrap_get_tiff_page_count(PyObject *self, PyObject *args) { const char *filename = NULL; gint pages; if (!PyArg_ParseTuple(args, "s", &filename)) return NULL; pages = get_tiff_page_count(filename); if (pages >= 1) { return Py_BuildValue("i", pages); } else { PyErr_SetString(PyExc_AssertionError, "Could not retrieve the page count of the tiff image."); return NULL; } } static PyObject * wrap_get_tiff_resolution(PyObject *self, PyObject *args) { const char *filename = NULL; gint page; gdouble xresolution, yresolution; if (!PyArg_ParseTuple(args, "si", &filename, &page)) return NULL; if (get_tiff_resolution(filename, page, &xresolution, &yresolution)) { return Py_BuildValue("dd", xresolution, yresolution); } else { PyErr_SetString(PyExc_AssertionError, "Could not retrieve the resolution for the tiff file and page."); return NULL; } } static PyObject * wrap_check_tiff_monochrome(PyObject *self, PyObject *args) { const char *filename = NULL; gboolean monochrome; if (!PyArg_ParseTuple(args, "s", &filename)) return NULL; monochrome = check_tiff_monochrome(filename); return Py_BuildValue("i", monochrome); } static PyObject * wrap_find_corner_marker(PyObject *self, PyObject *args) { PyObject *result; PycairoSurface *py_surface; PycairoMatrix *py_matrix; gint corner; gdouble corner_x, corner_y; gboolean success; if (!PyArg_ParseTuple(args, "O!O!i", &PycairoImageSurface_Type, &py_surface, &PycairoMatrix_Type, &py_matrix, &corner)) return NULL; success = find_corner_marker(py_surface->surface, &py_matrix->matrix, corner, &corner_x, &corner_y); if (success) { result = Py_BuildValue("dd", corner_x, corner_y); return result; } else { PyErr_SetString(PyExc_AssertionError, "Could not find corner marker!"); return NULL; } } static PyObject * wrap_calculate_correction_matrix_masked(PyObject *self, PyObject *args) { PyObject *result; PycairoSurface *py_surface; PycairoSurface *py_mask; PycairoMatrix *py_matrix; cairo_matrix_t *correction_matrix; float mm_x, mm_y; gdouble covered; if (!PyArg_ParseTuple(args, "O!O!O!ff", &PycairoImageSurface_Type, &py_surface, &PycairoImageSurface_Type, &py_mask, &PycairoMatrix_Type, &py_matrix, &mm_x, &mm_y)) return NULL; correction_matrix = calculate_correction_matrix_masked(py_surface->surface, py_mask->surface, &py_matrix->matrix, mm_x, mm_y, &covered); if (correction_matrix) { result = PycairoMatrix_FromMatrix(correction_matrix); g_free(correction_matrix); return Py_BuildValue("Nd", result, covered); } else { PyErr_SetString(PyExc_AssertionError, "Could not calculate the corrected matrix!"); return NULL; } } static PyObject * wrap_find_box_corners(PyObject *self, PyObject *args) { PycairoSurface *py_surface; PycairoMatrix *py_matrix; gdouble mm_x, mm_y, mm_width, mm_height; gdouble mm_x1, mm_y1, mm_x2, mm_y2, mm_x3, mm_y3, mm_x4, mm_y4; gboolean success; if (!PyArg_ParseTuple(args, "O!O!dddd", &PycairoImageSurface_Type, &py_surface, &PycairoMatrix_Type, &py_matrix, &mm_x, &mm_y, &mm_width, &mm_height)) return NULL; success = find_box_corners(py_surface->surface, &py_matrix->matrix, mm_x, mm_y, mm_width, mm_height, &mm_x1, &mm_y1, &mm_x2, &mm_y2, &mm_x3, &mm_y3, &mm_x4, &mm_y4); if (success) { return Py_BuildValue("(dd)(dd)(dd)(dd)", mm_x1, mm_y1, mm_x2, mm_y2, mm_x3, mm_y3, mm_x4, mm_y4); } else { PyErr_SetString(PyExc_AssertionError, "Could not find all the corners!"); return NULL; } } static PyObject * wrap_get_coverage(PyObject *self, PyObject *args) { PycairoSurface *py_surface; PycairoMatrix *py_matrix; gdouble mm_x, mm_y, mm_width, mm_height; gdouble coverage; if (!PyArg_ParseTuple(args, "O!O!dddd", &PycairoImageSurface_Type, &py_surface, &PycairoMatrix_Type, &py_matrix, &mm_x, &mm_y, &mm_width, &mm_height)) return NULL; coverage = get_coverage(py_surface->surface, &py_matrix->matrix, mm_x, mm_y, mm_width, mm_height); return Py_BuildValue("d", coverage); } static PyObject * wrap_get_masked_coverage(PyObject *self, PyObject *args) { PycairoSurface *py_surface; PycairoSurface *py_mask; gint x, y; gdouble coverage; if (!PyArg_ParseTuple(args, "O!O!ii", &PycairoImageSurface_Type, &py_surface, &PycairoImageSurface_Type, &py_mask, &x, &y)) return NULL; coverage = get_masked_coverage(py_surface->surface, py_mask->surface, x, y); return Py_BuildValue("d", coverage); } static PyObject * wrap_get_masked_coverage_without_lines(PyObject *self, PyObject *args) { PycairoSurface *py_surface; PycairoSurface *py_mask; gint x, y; gdouble line_width; gint line_count; gdouble coverage; if (!PyArg_ParseTuple(args, "O!O!iidi", &PycairoImageSurface_Type, &py_surface, &PycairoImageSurface_Type, &py_mask, &x, &y, &line_width, &line_count)) return NULL; coverage = get_masked_coverage_without_lines(py_surface->surface, py_mask->surface, x, y, line_width, line_count); return Py_BuildValue("d", coverage); } static PyObject * wrap_get_masked_white_area_count(PyObject *self, PyObject *args) { PycairoSurface *py_surface; PycairoSurface *py_mask; gint x, y; gdouble min_size, max_size; gdouble filled_area; int count; if (!PyArg_ParseTuple(args, "O!O!iidd", &PycairoImageSurface_Type, &py_surface, &PycairoImageSurface_Type, &py_mask, &x, &y, &min_size, &max_size)) return NULL; count = get_masked_white_area_count(py_surface->surface, py_mask->surface, x, y, min_size, max_size, &filled_area); return Py_BuildValue("id", count, filled_area); } static PyObject * wrap_get_pbm(PyObject *self, PyObject *args) { PycairoSurface *py_surface; PyObject* result; int length = 0; void *data = NULL; if (!PyArg_ParseTuple(args, "O!", &PycairoImageSurface_Type, &py_surface)) return NULL; get_pbm(py_surface->surface, &data, &length); result = Py_BuildValue("y#", data, length); g_free (data); return result; } static PyObject *sdaps_set_magic_values(PyObject *self, PyObject *args) { if (!PyArg_ParseTuple(args, "ddddd", &sdaps_line_min_length, &sdaps_line_max_length, &sdaps_line_width, &sdaps_corner_mark_search_distance, &sdaps_line_coverage)) return NULL; Py_INCREF(Py_None); return Py_None; } static PyObject *enable_debug_surface_creation(PyObject *self, PyObject *args) { if (!PyArg_ParseTuple(args, "i", &sdaps_create_debug_surface)) return NULL; Py_INCREF(Py_None); return Py_None; } static PyObject *get_debug_surface(PyObject *self, PyObject *args) { if (!PyArg_ParseTuple(args, "")) return NULL; if ((!sdaps_create_debug_surface) || (sdaps_debug_surface == NULL)) { Py_INCREF(Py_None); return Py_None; } else { PyObject *result; PyObject *pysurface; cairo_surface_reference(sdaps_debug_surface); pysurface = (PyObject*) PycairoSurface_FromSurface(sdaps_debug_surface, NULL); if (pysurface == NULL) return NULL; result = Py_BuildValue("Nii", pysurface, sdaps_debug_surface_ox, sdaps_debug_surface_oy); if (result == NULL) Py_DECREF(pysurface); return result; } } static PyObject * wrap_kfill_modified(PyObject *self, PyObject *args) { PycairoSurface *py_surface; gint k; if (!PyArg_ParseTuple(args, "O!i", &PycairoImageSurface_Type, &py_surface, &k)) return NULL; if (cairo_image_surface_get_format (py_surface->surface) != CAIRO_FORMAT_A1) { PyErr_SetString(PyExc_AssertionError, "This function only works with A1 surfaces currently!"); return NULL; } kfill_modified(py_surface->surface, k); Py_INCREF(Py_None); return Py_None; } sdaps-1.9.8/sdaps/log.py0000644000175000000660000001305613367301321015650 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . ''' This module alters sys.stdout and sys.stderr to copy all output into a logfile. Note that some magic is done when the output stream is not a tty. In that case the progress bar and messages done using the :py:meth:`interactive` function will be suppressed. The reason to do this is to allow commands to output data to `sys.stdout`. ''' import sys import time import io from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext def warn(msg): sys.stderr.write(_('Warning: ') + msg + '\n') def error(msg): sys.stderr.write(_('Error: ') + msg + '\n') def interactive(msg): """Only forward the message to stdout if it is a terminal.""" if hasattr(sys.stdout, "interactive"): sys.stdout.interactive(msg) else: if sys.stdout.isatty(): sys.stdout.write(msg) class Copier(object): '''copy all data going through the pipe into a logfile''' def __init__(self, pipe, logfile): self.pipe = pipe self.logfile = logfile def write(self, data): self.pipe.write(data) self.logfile.write(data) def interactive(self, data): if self.pipe.isatty(): self.pipe.write(data) self.logfile.write(data) def isatty(self): return self.pipe.isatty() def flush(self): self.pipe.flush() self.logfile.flush() def fileno(self): return self.pipe.fileno() class Wiper(object): '''wipe out the progressbar before forwarding data through the pipe''' def __init__(self, pipe, progressbar): self.pipe = pipe self.progressbar = progressbar def write(self, data): if self.progressbar.visible: self.pipe.write(' ' * 80) self.pipe.write('\r') self.progressbar.visible = 0 self.pipe.write(data) def isatty(self): return self.pipe.isatty() def flush(self): self.pipe.flush() def fileno(self): return self.pipe.fileno() class Encoder(object): '''Encode data going through the pipe to utf-8''' def __init__(self, pipe): self.pipe = pipe def write(self, data): if isinstance(data, bytes): self.pipe.write(data.encode('utf-8')) else: self.pipe.write(data) def close(self): self.pipe.close() def isatty(self): return self.pipe.isatty() def flush(self): self.pipe.flush() def fileno(self): return self.pipe.fileno() class Logfile(object): def __init__(self): self.logfile = io.StringIO() def write(self, data): self.logfile.write(data) self.logfile.flush() def open(self, filename): logfile = Encoder(open(filename, 'a')) logfile.write(self.logfile.getvalue()) self.logfile = logfile def close(self): self.logfile.close() self.logfile = io.StringIO() def isatty(self): return False def flush(self): self.logfile.flush() def fileno(self): return self.logfile.fileno() class ProgressBar(object): def __init__(self, pipe): self.pipe = pipe self.visible = 0 def start(self, max_value): self.max_value = max_value self.start_time = time.time() self.update(0) def update(self, value): self.elapsed_time = time.time() - self.start_time # Don't display anything if the output is a pipe if not self.pipe.isatty(): return progress = float(value) / float(self.max_value) self.pipe.write('|') self.pipe.write(('#' * int(round(progress * 64))).ljust(64)) self.pipe.write('| ') self.pipe.write(('%i%% ' % int(round(progress * 100))).rjust(5)) if progress == 0: self.pipe.write('--:--:--') elif progress == 1: self.pipe.write(time.strftime('%H:%M:%S', time.gmtime(self.elapsed_time))) self.pipe.write('\n') else: remaining_time = self.elapsed_time * (1 / progress - 1) self.pipe.write(time.strftime('%H:%M:%S', time.gmtime(remaining_time))) self.pipe.write('\r') self.pipe.flush() self.visible = 1 def isatty(self): return self.pipe.isatty() def flush(self): self.pipe.flush() progressbar = ProgressBar(sys.stdout) logfile = Logfile() redirects_activated = False def activate_redirects(): global redirects_activated if redirects_activated is not False: return redirects_activated = True sys.stdout = Encoder(sys.stdout) sys.stderr = Encoder(sys.stderr) sys.stdout = Wiper(sys.stdout, progressbar) sys.stderr = Wiper(sys.stderr, progressbar) sys.stdout = Copier(sys.stdout, logfile) sys.stderr = Copier(sys.stderr, logfile) sdaps-1.9.8/sdaps/matrix.py0000644000175000000660000000747413367301321016402 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """ The matrix module adds support to find out rotation matrix for a scanned page. After loading this module you can access the transformation matrices (cairo.Martrix instances) via two functions: :py:meth:`model.sheet.Image.matrix.mm_to_px` and :py:meth:`model.sheet.Image.matrix.px_to_mm` The return value of :py:meth:`mm_to_px` can be used to convert millimeter values to pixel on the scanned page. :py:meth:`px_to_mm` returns the inverse matrix to convert on page pixels to millimeter values of the original document. Both the millimeter and pixel spaces start at the top left corner of the page. Warning: The correct values are only available after "recognize" has been run! """ import cairo from sdaps import model from sdaps import surface from sdaps import image class Image(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'matrix' obj_class = model.sheet.Image def mm_to_px(self, fallback=True): """Return the matrix to convert mm to pixel space. If no matrix information is available and `fallback` is set to `True` then a matrix will be calculated from the size of the image.""" matrix = self.px_to_mm(fallback) if matrix is not None: matrix.invert() return matrix def px_to_mm(self, fallback=True): """Return the matrix to convert pixel to mm space. If no matrix information is available and `fallback` is set to `True` then a matrix will be calculated from the size of the image.""" if self.obj.raw_matrix is not None: return cairo.Matrix(*self.obj.raw_matrix) elif fallback: # Return a dummy matrix ... that maps the image to the page size width, height = self.obj.surface.get_size() xres, yres = image.get_tiff_resolution( self.obj.sheet.survey.path(self.obj.filename), self.obj.tiff_page) if xres == 0 or yres == 0: xres = width / self.obj.sheet.survey.defs.paper_width yres = height / self.obj.sheet.survey.defs.paper_height scan_width = width / xres scan_height = height / yres dx = (self.obj.sheet.survey.defs.paper_width - scan_width) / 2.0 dy = (self.obj.sheet.survey.defs.paper_height - scan_height) / 2.0 matrix = cairo.Matrix() # Center the image matrix.translate(dx, dy) matrix.scale(1.0 / xres, 1.0 / yres) return matrix else: return None def matrix_valid(self): """Checks whether the proper transformation matrix is known.""" return self.obj.raw_matrix != None def set_px_to_mm(self, matrix): """Set the stored matrix for the image. You need to pass in the pixel to mm space conversion matrix. Unsetting can be done by passing `None`. """ if matrix is not None: self.obj.raw_matrix = tuple(matrix) else: self.obj.raw_matrix = None sdaps-1.9.8/sdaps/model/0000755000175000000660000000000013611127124015607 5ustar benjaminlock00000000000000sdaps-1.9.8/sdaps/model/__init__.py0000644000175000000660000000444113367301321017724 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . '''data model for sdaps Survey ====== survey :: +-- questionnaire | +-- qobjects ---------------+ | +-- boxes ----------+ +-- sheets | +-- data dictionary | | +-- data objects <--+ +-- images The questionnaire tree resembles the structer of the questionnaire and the internal structure of the programm. It is set up by the setup script and not altered(much) later. The sheets tree holds the data of the answered questionnaires. The sheet objects are created while the scanned images are added to the project. Iterating through sheets and jumping ==================================== Survey provides a function iterate. It iterates through the sheets and calls a function for each. Inside this function, the sheet is accessible through survey.sheet(a property, pointing to the actual sheet) The functions goto_something jump the survey.sheet pointer to the specified sheet. Buddies ======= A script may define a buddy class for a class in the model. Then each object of that model class is accompanied by an object of the buddy class. The buddy object is instanciated automatically upon first access and then cached. It is not saved on disc. The buddy system allows you to define additional methods and attributes for the objects in the model. ''' from . import buddy from . import data from . import questionnaire from . import sheet from . import survey sdaps-1.9.8/sdaps/model/buddy.py0000644000175000000660000000444013367301321017273 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . ''' sdaps - scripts for data acquisition with paper based surveys model/buddy - Registration center for buddies Defining a buddy ================ from sdaps import model class QObject(model.buddy.Buddy): __metaclass__ = model.buddy.Register obj_class = object class name = 'my_buddy' The buddy will be available as object.my_buddy Inside buddy class, the object is available as self.obj ''' class Object(object): '''class which can have buddies''' def get_buddy(self, name): try: return getattr(self, '_%s_object_' % name) except AttributeError: setattr(self, '_%s_object_' % name, getattr(self, '_%s_class_' % name)(self)) return getattr(self, '_%s_object_' % name) class Register(type): '''metaclass to register the class as a buddy''' def __init__(cls, name, bases, dict): type.__init__(cls, name, bases, dict) assert issubclass(cls.obj_class, Object) setattr( cls.obj_class, '_%s_class_' % cls.name, cls ) setattr( cls.obj_class, cls.name, property(lambda self: self.get_buddy(cls.name)) ) class Buddy(object, metaclass=Register): '''base class for buddies''' obj_class = Object name = 'my_buddy' def __init__(self, obj): if 0: assert isinstance(obj, self.obj_class) self.obj = obj sdaps-1.9.8/sdaps/model/data.py0000644000175000000660000000433313450366236017107 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . class QObject(object): def __init__(self, parent): self.review_comment = '' @property def empty(self): return not self.review_comment class Box(object): def __init__(self, parent): self.state = 0 self.metrics = dict() self.quality = 1 self.x = parent.x self.y = parent.y self.width = parent.width self.height = parent.height # Set _parent last, so that we don't trigger notifications # during __init__ self._parent = parent def __setattr__(self, name, value): if hasattr(self, name): old_value = getattr(self, name) else: old_value = None object.__setattr__(self, name, value) # private if name.startswith('_'): return if value != old_value and hasattr(self, '_parent') and self._parent is not None: self._dirty = True self._parent.question.questionnaire.notify_data_changed(self._parent, self, name, old_value) @property def empty(self): return not self.state class Checkbox(Box): pass class Textbox(Box): def __init__(self, parent): self.text = str() Box.__init__(self, parent) class Additional_Mark(object): def __init__(self, parent): self.value = 0 @property def empty(self): return self.value == 0 sdaps-1.9.8/sdaps/model/db.py0000644000175000000660000000417613473751331016567 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2018, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from types import ModuleType def toJson(obj): if hasattr(obj, '__slots__'): res = dict() for slot in getattr(obj, '__slots__'): res[slot] = getattr(obj, slot) else: if hasattr(obj, '_save_attrs'): attrs = getattr(obj, '_save_attrs') res = dict() for attr in attrs: res[attr] = getattr(obj, attr) else: if hasattr(obj, '_save_skip'): skip = getattr(obj, '_save_skip') else: skip = set() res = obj.__dict__.copy() keys = list(res.keys()) for key in keys: if key.startswith('_') or key in skip: del res[key] if hasattr(obj, '__to_json_state__'): obj.__to_json_state__(res) res['_class'] = obj.__class__.__name__ return res def fromJson(data, module_or_class): if isinstance(module_or_class, ModuleType): cls = getattr(module_or_class, data['_class']) else: cls = module_or_class obj = cls.__new__(cls) del data['_class'] if hasattr(cls, '__setstate__'): getattr(cls, '__setstate__') cls.__setstate__(obj, data) elif hasattr(obj, '__slots__'): for k, v in data.items(): setattr(obj, k, v) else: obj.__dict__.update(data) return obj sdaps-1.9.8/sdaps/model/questionnaire.py0000644000175000000660000003054713473752177021102 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # The code uses multiple inheritance; however, most of the additional base # classes are solely used as mixins. This means they must not contain any # __init__ functions, as that could cause trouble. from . import db from . import buddy from . import data import sys import struct class DataObject(object): '''Mixin ''' def get_data(self): if not self.id in self.sheet.data: if hasattr(self, '_data_object'): clsname = self._data_object else: clsname = self.__class__.__name__ self.sheet.data[self.id] = getattr(data, clsname)(self) return self.sheet.data[self.id] data = property(get_data) class Questionnaire(buddy.Object): ''' Identification: There is only one. Reference: survey.questionnaire Parent: self.survey ''' _save_skip = {'survey'} def __init__(self): self.survey = None self.qobjects = list() self.last_id = (-1,) self.init_attributes() self._notify_changed_list = list() def init_attributes(self): self.page_count = 0 def add_qobject(self, qobject, new_id=None): qobject.questionnaire = self # XXX: Is this any good? if new_id is not None: assert new_id > self.last_id self.last_id = new_id qobject.id = new_id else: self.last_id = qobject.init_id(self.last_id) self.qobjects.append(qobject) def get_sheet(self): return self.survey.sheet sheet = property(get_sheet) def notify_data_changed(self, qobj, dobj, name, old_value): for func in self._notify_changed_list: func(self, qobj, dobj, name, old_value) def connect_data_changed(self, func): self._notify_changed_list.append(func) def disconnect_data_changed(self, func): self._notify_changed_list.remove(func) def __str__(self): return str().join( ['%s\n' % self.__class__.__name__] + [str(qobject) for qobject in self.qobjects] ) def find_object(self, oid): for qobject in self.qobjects: obj = qobject.find_object(oid) if obj is not None: return obj def reinit_state(self): self._notify_changed_list = list() def __setstate__(self, data): self.__dict__.update(data) self._notify_changed_list = list() for i in range(len(self.qobjects)): self.qobjects[i] = db.fromJson(self.qobjects[i], sys.modules[__name__]) self.qobjects[i].questionnaire = self class QObject(buddy.Object, DataObject): ''' Identification: id ==(major, minor) Reference: survey.questionnaire.qobjects[i](i != id) Parent: self.questionnaire ''' _data_object = 'QObject' _save_skip = {'survey', 'questionnaire'} def __init__(self): self.questionnaire = None self.boxes = list() self.last_id = -1 self.max_value = -1 self.var = None self.init_attributes() def init_attributes(self): pass def init_id(self, id): self.id = id[:-1] + (id[-1] + 1,) return self.id def add_box(self, box): box.question = self self.last_id = box.init_id(self.last_id) self.max_value = max(self.max_value, box.init_value(self.max_value)) self.boxes.append(box) def get_sheet(self): return self.questionnaire.sheet sheet = property(get_sheet) def calculate_survey_id(self, md5): pass def id_str(self): ids = [str(x) for x in self.id] return '.'.join(ids) def id_csv(self): if self.var: return self.var ids = [str(x) for x in self.id] return '_'.join(ids) def id_filter(self): ids = [str(x) for x in self.id] return '_' + '_'.join(ids) def __str__(self): return '(%s)\n' % ( self.__class__.__name__, ) def find_object(self, oid): if self.id == oid: return self for box in self.boxes: obj = box.find_object(oid) if obj is not None: return obj return None def __setstate__(self, data): # Attributes that may not (yet) be present in the database self.var = None self.__dict__.update(data) self.id = tuple(self.id) for i in range(len(self.boxes)): self.boxes[i] = db.fromJson(self.boxes[i], sys.modules[__name__]) self.boxes[i].question = self class Head(QObject): def init_attributes(self): QObject.init_attributes(self) self.title = str() def init_id(self, id): self.id = (id[0] + 1, ) + (0,)*(len(id)-1) return self.id def __str__(self): return '%s(%s) %s\n' % ( self.id_str(), self.__class__.__name__, self.title, ) class Question(QObject): def init_attributes(self): QObject.init_attributes(self) self.page_number = 0 self.question = str() def calculate_survey_id(self, md5): for box in self.boxes: box.calculate_survey_id(md5) def __str__(self): return '%s(%s) %s {%i}\n' % ( self.id_str(), self.__class__.__name__, self.question, self.page_number ) class Choice(Question): def __str__(self): return str().join( [Question.__str__(self)] + [str(box) for box in self.boxes] ) def get_answer(self): '''it's a list containing all selected values ''' answer = list() for box in self.boxes: if box.data.state: answer.append(box.value) return answer class Option(Question): def init_attributes(self): Question.init_attributes(self) self.value_none = -1 self.value_invalid = -2 def __str__(self): return str().join( [Question.__str__(self)] + [str(box) for box in self.boxes] ) def get_answer(self): answer = list() for box in self.boxes: if box.data.state: answer.append(box.value) if len(answer) == 1: return answer[0] else: if len(answer) == 0: return self.value_none else: return self.value_invalid def set_answer(self, answer): # Used for CSV import. Set the first box with the right value, unset # all others. # Raises an exception if not found # Unset all if value is the none value if answer == self.value_none: for box in self.boxes: box.data.state = 0 return # Set all if value is the none value # NOTE: Assumes more than one box! if answer == self.value_invalid: assert len(self.boxes) > 1 for box in self.boxes: box.data.state = 1 return found = False for box in self.boxes: if not found and box.value == answer: found = True box.data.state = 1 else: box.data.state = 0 assert(found) class Range(Option): def init_attributes(self): Option.init_attributes(self) self.answers = ("", "") self.range = (0, 0) def __str__(self): if len(self.answers) == 2: return str().join( [Question.__str__(self)] + ['\t%s (%i) - %s (%i)\n' % (self.answers[0], self.range[0], self.answers[1], self.range[1])] + [str(box) for box in self.boxes] ) else: return str().join( [Question.__str__(self)] + ['\t? - ?\n'] + [str(box) for box in self.boxes] ) class Mark(Range): # Just an alias for unpickling old data pass class Text(Question): def __str__(self): return str().join( [Question.__str__(self)] + [str(box) for box in self.boxes] ) def get_answer(self): '''it's a bool, wether there is content in the textbox ''' assert len(self.boxes) == 1 text = "" for box in self.boxes: text = text + box.data.text if text: return text else: return self.boxes[0].data.state class Additional_Head(Head): pass class Additional_Mark(Question): def init_attributes(self): Question.init_attributes(self) self.answers = list() def __str__(self): return str().join( [Question.__str__(self)] + ['\t%s - %s\n' % tuple(self.answers)] ) def get_answer(self): return self.data.value def set_answer(self, answer): self.data.value = answer class Additional_FilterHistogram(Question): def init_attributes(self): Question.init_attributes(self) self.answers = list() self.filters = list() def __str__(self): result = [] result.append(Question.__str__(self)) for i in range(len(self.answers)): result.append('\t%s - %s\n' % (self.answers[i], self.filters[i])) return str().join(result) def get_answer(self): return self.data.value def set_answer(self, answer): raise NotImplemented() class Box(buddy.Object, DataObject): ''' Identification: id of the parent and value of the box :: id == (major, minor, value) Reference: survey.questionnaire.qobjects[i].boxes[j] Parent: self.question ''' _save_skip = { 'question' } def __init__(self): self.question = None self.init_attributes() def init_attributes(self): self.page_number = 0 self.x = 0 self.y = 0 self.width = 0 self.height = 0 self.lw = 25.4 / 72.0 self.text = str() self.var = None self.value = None def init_id(self, id): id = id + 1 self.id = self.question.id + (id,) return id def init_value(self, value): value = value + 1 if self.value is None: self.value = value return self.value def id_str(self): ids = [str(x) for x in self.id] return '.'.join(ids) def id_csv(self): if self.var: return self.var ids = [str(x) for x in self.id] return '_'.join(ids) def get_sheet(self): return self.question.sheet sheet = property(get_sheet) def calculate_survey_id(self, md5): tmp = struct.pack('!ffff', self.x, self.y, self.width, self.height) md5.update(tmp) def __str__(self): return '\t%i(%s) %s %s %s %s %s\n' % ( self.value, (self.__class__.__name__).ljust(8), ('%.1f' % self.x).rjust(5), ('%.1f' % self.y).rjust(5), ('%.1f' % self.width).rjust(5), ('%.1f' % self.height).rjust(5), self.text ) def find_object(self, oid): if self.id == oid: return self def __setstate__(self, data): self.__dict__.update(data) self.id = tuple(self.id) class Checkbox(Box): def init_attributes(self): Box.init_attributes(self) self.form = "box" def calculate_survey_id(self, md5): Box.calculate_survey_id(self, md5) md5.update(self.form.encode('utf-8')) class Textbox(Box): pass class Codebox(Textbox): _data_object = 'Textbox' sdaps-1.9.8/sdaps/model/sheet.py0000644000175000000660000001467613473752174017326 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from . import buddy from . import data as datamodule from . import db class Sheet(buddy.Object): _save_attrs = {'data', 'images', 'survey_id', 'questionnaire_id', 'global_id', 'valid', 'quality', 'recognized', 'review_comment' } def __init__(self): self.survey = None self.data = dict() self.images = list() self.survey_id = None self.questionnaire_id = None self.global_id = None self.valid = 1 self.quality = 1 self.review_comment = None self.recognized = False def add_image(self, image): self.images.append(image) image.sheet = self def get_page_image(self, page): # Simply return the image for the requested page. # Note: We return the first one we find; this means in the error case # that a page exists twice, we return the first one. for image in self.images: if image.page_number == page and image.survey_id == self.survey.survey_id: return image return None def reinit_state(self): for k, v in self.data.items(): obj = self.survey.questionnaire.find_object(k) v._parent = obj @classmethod def __to_json_state__(cls, state): # json is unable to serialize our tuples as keys, so make strings with # '^' as a separator. orig_data = state['data'] state['data'] = dict() for k, v in orig_data.items(): state['data']['^'.join(str(_) for _ in k)] = v def __setstate__(self, data): # Attributes that may not (yet) be present in the database self.survey = None self.review_comment = None _tmp = data['data'] data['data'] = dict() for k, v in _tmp.items(): data['data'][tuple(int(_) for _ in k.split('^'))] = db.fromJson(v, datamodule) for k in range(len(data['images'])): data['images'][k] = db.fromJson(data['images'][k], Image) data['images'][k].sheet = self # Migrate old "verified" flag if 'verified' in data: for img in data['images']: img.verified = data['verified'] del data['verified'] self.__dict__.update(data) @property def verified(self): for img in self.images: if img.ignored: continue if not img.verified: return False return True @property def empty(self): for k, v in self.data.items(): if not v.empty: return False return True @property def complete(self): """A boolean whether this sheet is complete in the sense that every page of the questionnaire has been identified. ie. it is false if there are missing pages""" # Simply retrieve every page, and see if it is not None for page in range(self.survey.questionnaire.page_count): if self.get_page_image(page + 1) is None: return False return True @property def dirty(self): if hasattr(self, '_dirty'): return True for d in self.data.values(): if hasattr(d, '_dirty'): return True for i in self.images: if hasattr(i, '_dirty'): return True def _clear_dirty(self): if hasattr(self, '_dirty'): del self._dirty for d in self.data.values(): if hasattr(d, '_dirty'): del d._dirty for i in self.images: if hasattr(i, '_dirty'): del i._dirty def __setattr__(self, attr, value): if attr.startswith('_') or attr == 'survey': object.__setattr__(self, attr, value) return # Nonexisting attributes should never be set. assert attr in self._save_attrs self.__setattr__('_dirty', True) # We need to fall back to "None" for __init__ to work. try: old_value = getattr(self, attr) force = False except AttributeError: old_value = None force = True if force or value != old_value: object.__setattr__(self, attr, value) # survey may be None if the sheet does not belong to a survey yet. if self.survey is not None: self.survey.questionnaire.notify_data_changed(None, None, attr, old_value) class Image(buddy.Object): # Could make "sheet" a private property instead! _save_skip = {'sheet'} def __init__(self): self.sheet = None self.filename = str() self.tiff_page = 0 self.rotated = 0 self.raw_matrix = None self.page_number = None self.survey_id = None self.global_id = None self.questionnaire_id = None #: Whether the page should be ignored (because it is a blank back side) self.ignored = False self.verified = False def __setattr__(self, attr, value): if attr.startswith('_'): return object.__setattr__(self, attr, value) if attr != 'sheet': object.__setattr__(self, '_dirty', True) try: old_value = getattr(self, attr) except AttributeError: old_value = None object.__setattr__(self, attr, value) # survey may be None if the sheet does not belong to a survey yet. if hasattr(self, "sheet") and self.sheet is not None and self.sheet.survey is not None: self.sheet.survey.questionnaire.notify_data_changed(None, None, attr, old_value) sdaps-1.9.8/sdaps/model/survey.py0000644000175000000660000004262013566251707017540 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008,2018, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import os import sys import struct import json import sqlite3 import weakref from contextlib import closing from . import db from . import questionnaire from .sheet import Sheet from sdaps import defs from sdaps import log from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext valid_styles = ['classic', 'code128', 'custom', 'qr'] valid_checkmodes = ['checkcorrect', 'check', 'fill'] # Note that row_id has the same value as the implicit rowid row. _db_schema = """ CREATE TABLE surveys ( row_id INTEGER PRIMARY KEY AUTOINCREMENT, json TEXT ); CREATE TRIGGER survey_delete AFTER DELETE ON surveys FOR EACH ROW BEGIN DELETE FROM sheets WHERE survey_rowid = OLD.row_id; END; CREATE TABLE sheets ( survey_rowid REFERENCES surveys(row_id) NOT NULL, sort INTEGER(8), json TEXT ); """ class Defs(object): """General definitions that are valid for this survey. :ivar paper_width: Width of the paper in mm. :ivar paper_height: Height of the paper in mm. :ivar print_questionnaire_id: Whether a questionnaire ID is printed on each sheet. :ivar print_survey_id: Whether a survey ID is printed on each sheet. :ivar style: The style that is used for ID marking. :ivar duplex: Whether the questionnaire is duplex or not. """ # Force a certain set of options using slots __slots__ = ['paper_width', 'paper_height', 'print_questionnaire_id', 'print_survey_id', 'style', 'duplex', 'checkmode', 'engine'] def get_survey_id_pos(self): assert(self.style == 'classic') y_pos = self.paper_height - defs.corner_mark_bottom - defs.corner_box_padding y_pos -= defs.codebox_height left_padding = defs.corner_mark_left + 2 * defs.corner_box_padding + defs.corner_box_width right_padding = defs.corner_mark_right + 2 * defs.corner_box_padding + defs.corner_box_width text_y_pos = y_pos + defs.codebox_text_baseline_shift x_center = left_padding + (self.paper_width - left_padding - right_padding) / 2.0 msb_box_x = left_padding lsb_box_x = self.paper_width - right_padding - defs.codebox_width text_x_pos = left_padding + (self.paper_width - right_padding - left_padding) / 2 return msb_box_x, lsb_box_x, y_pos, text_x_pos, text_y_pos def get_questionnaire_id_pos(self): assert(self.style == 'classic') msb_box_x, lsb_box_x, y_pos, text_x_pos, text_y_pos = self.get_survey_id_pos() if self.print_survey_id: # Just move the y positions up if neccessary y_pos -= defs.codebox_height + defs.corner_box_padding text_y_pos -= defs.codebox_height + defs.corner_box_padding return msb_box_x, lsb_box_x, y_pos, text_x_pos, text_y_pos class Survey(object): """The main survey object. :ivar defs: The :py:class:`model.survey.Defs` instance for this survey. :ivar survey_id: The survey ID of this survey. :ivar global_id: The global ID set for this survey. It is used during the "stamp" step. :ivar questionnaire: The py:class:`model.questionnaire.Questionnaire` instance representing the questionnaire. :ivar title: The title of the survey. :ivar info: Dictionary with general information about the survey. :ivar questionnaire_ids: A List of used questionnaire IDs. """ _pickled_attrs = set(('defs', 'survey_id', 'questionnaire_ids', 'questionnaire', 'version')) def __init__(self): self.questionnaire = None self._internal_init() self.title = str() self.info = dict() self.survey_id = 0 self.global_id = None self.questionnaire_ids = list() self.index = 0 self.defs = Defs() self._db = None # Hardcoded for now. self._survey_rowid = 0 def _internal_init(self): self._loaded_sheets = weakref.WeakValueDictionary() self._dirty_sheets = [] self._current_sheet = None def add_questionnaire(self, questionnaire): self.questionnaire = questionnaire questionnaire.survey = self def add_sheet(self, sheet): """" WARNING: It is impossible to iterate newly added sheets before the survey has been saved! """ sheet.survey = self sheet._rowid = -1 self.goto_sheet(sheet) def delete_sheet(self, sheet): """" WARNING: The sheet will remain iteratable until the survey has been saved! """ # This is a bit of a hack, but it will work great sheet._delete = True sheet._dirty = True self.goto_sheet(None) def calculate_survey_id(self): """Calculate the unique survey ID from the surveys settings and boxes. The ID only includes the boxes positions, which means that simple typo fixes will not change the ID most of the time.""" import hashlib md5 = hashlib.new('md5') for qobject in self.questionnaire.qobjects: qobject.calculate_survey_id(md5) for defs_slot in self.defs.__slots__: # Backward compatibility if defs_slot == 'checkmode' and self.defs.checkmode == "checkcorrect": continue if defs_slot == 'engine': continue if isinstance(self.defs.__getattribute__(defs_slot), float): md5.update(str(round(self.defs.__getattribute__(defs_slot), 1)).encode('utf-8')) else: md5.update(str(self.defs.__getattribute__(defs_slot)).encode('utf-8')) # Use the first 32 bits as a little endian unsigned integer self.survey_id = struct.unpack(' 6: print(_("The 'classic' style only supports a maximum of six pages! Use the 'code128' style if you require more pages.")) return False return True def validate_questionnaire_id(self, qid): """Do style specific sanity checks on the questionnaire ID.""" if self.defs.style == "classic": # The ID needs to be an integer try: return int(qid) except ValueError: log.error(_("IDs need to be integers in \"classic\" style!")) sys.exit(1) elif self.defs.style == "code128": # Check each character for validity for c in str(qid): if not c in defs.c128_chars: log.error(_("Invalid character %s in questionnaire ID \"%s\" in \"code128\" style!") % (c, qid)) sys.exit(1) return qid elif self.defs.style == "custom": log.error(_("SDAPS cannot draw a questionnaire ID with the \"custom\" style. Do this yourself somehow!")) sys.exit(1) elif self.defs.style == "qr": return qid else: AssertionError() sdaps-1.9.8/sdaps/paths.py0000644000175000000660000000575413367301321016214 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . '''Some path values, used to find and load program components. ''' import os import gettext import locale local_run = False # required if local_run == True build_dir = str() # required if local_run == True lib_build_dir = str() # required if local_run == True source_dir = str() # required if local_run == False prefix = str() def init(local_run_value, package_path): '''Initialize path values for sdaps ''' global local_run, build_dir, lib_build_dir, source_dir, prefix # Initialize local_run local_run = local_run_value base_dir = os.path.split(os.path.abspath(package_path))[0] if local_run: source_dir = base_dir from pkg_resources import get_build_platform from distutils.sysconfig import get_python_version # Initialize gettext init_gettext(os.path.join( base_dir, 'build', 'mo')) # Initialize build_dir build_dir = os.path.join(base_dir, 'build', 'share', 'sdaps') # Initialize build_dir lib_build_dir = os.path.join( base_dir, 'build', 'lib.%s-%s' % (get_build_platform(), get_python_version()), 'sdaps') else: # Look for the data in the parent directories path = base_dir while True: if os.path.exists(os.path.join(path, 'share', 'sdaps')): prefix = path break new_path = os.path.split(path)[0] assert not path == new_path, "could not find locales" # Wir wären oben angekommen path = new_path # Initialize gettext init_gettext(os.path.join(prefix, 'share', 'locale')) def init_gettext(locale_dir): '''Initialize gettext using the given directory containing the l10n data. ''' gettext.bindtextdomain('sdaps', locale_dir) if hasattr(gettext, 'bind_textdomain_codeset'): gettext.bind_textdomain_codeset('sdaps', 'UTF-8') gettext.textdomain('sdaps') if hasattr(locale, 'bind_textdomain_codeset'): locale.bindtextdomain('sdaps', locale_dir) locale.bind_textdomain_codeset('sdaps', 'UTF-8') locale.textdomain('sdaps') sdaps-1.9.8/sdaps/recognize/0000755000175000000660000000000013611127124016474 5ustar benjaminlock00000000000000sdaps-1.9.8/sdaps/recognize/__init__.py0000644000175000000660000000263413367301321020613 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """ This module adds the functionality to automatically recognize the scanned image data. It reads the image data and tries to guess whether a checkbox is empty/checked/filled and finds the written area in a textfield. """ from sdaps import model from . import buddies def recognize(survey, filter): # iterate over sheets survey.iterate_progressbar(survey.questionnaire.recognize.recognize, filter) survey.save() def identify(survey, filter): # iterate over sheets survey.iterate_progressbar(survey.questionnaire.recognize.identify, filter) survey.save() sdaps-1.9.8/sdaps/recognize/blank.py0000644000175000000660000000503313367301321020137 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008,2013, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # Example of using this to preload your own custom buddy. This first sets up the # paths, below the call into sdaps happens if __name__ == '__main__': import sys import os sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..')) from sdaps import defs from sdaps import model from sdaps.utils.exceptions import RecognitionError from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext class Image(model.buddy.Buddy, metaclass=model.buddy.Register): """Example buddy class for a "blank" style. It simply assumes that everything is good about the page. ie. first page, no rotation, correct survey ID, and no other IDs.""" name = 'style' obj_class = model.sheet.Image def get_page_rotation(self): """Return the rotation of the passed image.""" # Assume not rotated return False def get_page_number(self): """Return page number or None if not known.""" # Assume only one page return 1 def get_survey_id(self): """Return the survey ID as read from the image, or None.""" # Return the expected survey ID return self.obj.sheet.survey.survey_id def get_questionnaire_id(self): """Return the questionnaire ID as read from the image.""" # Assume no (useful) questionnaire ID exists return None def get_global_id(self): """Return the global ID as read from the image.""" # Assume no (useful) global ID exists return None # Example of using this to preload your own custom buddy. This assume a local run. # You can of course use the API directly too. if __name__ == '__main__': import sdaps sys.exit(sdaps.main(local_run = True)) sdaps-1.9.8/sdaps/recognize/buddies.py0000644000175000000660000010601613575707425020512 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008,2011, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import cairo import math from sdaps import model from sdaps import matrix from sdaps import surface from sdaps import image from sdaps import defs from sdaps.utils.exceptions import RecognitionError from sdaps import log from sdaps.utils.barcode import read_barcode from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext pt_to_mm = 25.4 / 72.0 warned_multipage_not_correctly_scanned = False class Sheet(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'recognize' obj_class = model.sheet.Sheet def __init__(self, *args): model.buddy.Buddy.__init__(self, *args) self.filter_image = None def recognize(self): global warned_multipage_not_correctly_scanned self.obj.valid = 1 duplex_mode = self.obj.survey.defs.duplex # Load all images of this sheet for image in self.obj.images: if not image.ignored: image.rotated = 0 image.surface.load() failed_pages = set() # Matrix recognition for all of them matrix_errors = set() for page, image in enumerate(self.obj.images): try: image.recognize.calculate_matrix() except RecognitionError: matrix_errors.add(page) # We need to check the matrix_errors. Some are expected in simplex mode for page in matrix_errors: # in simplex mode every page will have a matrix; it might be a None # matrix though log.warn(_('%s, %i: Matrix not recognized.') % (self.obj.images[page].filename, self.obj.images[page].tiff_page)) failed_pages.add(page) # Rotation for all of them for page, image in enumerate(self.obj.images): try: # This may set the rotation to "None" for unknown image.recognize.calculate_rotation() except RecognitionError: log.warn(_('%s, %i: Rotation not found.') % (image.filename, image.tiff_page)) failed_pages.add(page) # Copy the rotation over (if required) and print warning if the rotation is unknown self.duplex_copy_image_attr(failed_pages, 'rotated', _("Neither %s, %i or %s, %i has a known rotation!")) # Reload any image that is rotated. for page, image in enumerate(self.obj.images): if image.rotated and not image.ignored: image.surface.load() # And redo the whole matrix stuff ... # XXX: It would be better to manipulate the matrix instead. try: image.recognize.calculate_matrix() except RecognitionError: if duplex_mode: log.warn(_('%s, %i: Matrix not recognized (again).') % (image.filename, image.tiff_page)) failed_pages.add(page) ############ # At this point we can extract the page numbers and IDs as neccessary. ############ # Figure out the page numbers # *************************** for page, image in enumerate(self.obj.images): try: # This may set the page_number to "None" for unknown image.recognize.calculate_page_number() except RecognitionError: log.warn(_('%s, %i: Could not get page number.') % (image.filename, image.tiff_page)) image.page_number = None failed_pages.add(page) i = 0 while i < len(self.obj.images): # We try to recover at least the page number of failed pages # this way. # NOTE: In simplex mode dummy pages will be inserted, so one page # always has no page number, and the other one has one. # This is exactly what we want, so we don't need to do anything # (except warn if we did not find any page!) failed = (i in failed_pages or i + 1 in failed_pages) first = self.obj.images[i] second = self.obj.images[i + 1] if first.page_number is None and second.page_number is None: if not failed: # Whoa, that should not happen. log.warn(_("Neither %s, %i or %s, %i has a known page number!" % (first.filename, first.tiff_page, second.filename, second.tiff_page))) failed_pages.add(i) failed_pages.add(i + 1) elif duplex_mode == False: # Simplex mode is special, as we know that one has to be unreadable # we need to ensure one of the page numbers is None if first.page_number is not None and second.page_number is not None: # We don't touch the ignore flag in this case # Simply print a message as this should *never* happen log.error(_("Got a simplex document where two adjacent pages had a known page number. This should never happen as even simplex scans are converted to duplex by inserting dummy pages. Maybe you did a simplex scan but added it in duplex mode? The pages in question are %s, %i and %s, %i.") % (first.filename, first.tiff_page, second.filename, second.tiff_page)) # Set the ignored flag for the unreadable page. This is a valid # operation as the back side of a readable page is known to be # empty. elif first.page_number is None: first.ignored = True else: second.ignored = True elif first.page_number is None: # One based, odd -> +1, even -> -1 first.page_number = second.page_number - 1 + 2 * (second.page_number % 2) elif second.page_number is None: second.page_number = first.page_number - 1 + 2 * (first.page_number % 2) elif first.page_number != (second.page_number - 1 + 2 * (second.page_number % 2)): if not failed: log.warn(_("Images %s, %i and %s, %i do not have consecutive page numbers!" % (first.filename, first.tiff_page, second.filename, second.tiff_page))) failed_pages.add(i) failed_pages.add(i + 1) i += 2 # Check that every page has a non None value, and each page exists once. pages = set() for i, image in enumerate(self.obj.images): # Ignore known blank pages if image.ignored: continue if image.page_number is None: log.warn(_("No page number for page %s, %i exists." % (image.filename, image.tiff_page))) failed_pages.add(i) continue if image.page_number in pages: log.warn(_("Page number for page %s, %i already used by another image.") % (image.filename, image.tiff_page)) failed_pages.add(i) continue if image.page_number <= 0 or image.page_number > self.obj.survey.questionnaire.page_count: log.warn(_("Page number %i for page %s, %i is out of range.") % (image.page_number, image.filename, image.tiff_page)) failed_pages.add(i) continue pages.add(image.page_number) # Figure out the suvey ID if neccessary # ************************************* if self.obj.survey.defs.print_survey_id: for page, image in enumerate(self.obj.images): try: if not duplex_mode or (image.page_number is not None and image.page_number % 2 == 0): image.recognize.calculate_survey_id() else: image.survey_id = None except RecognitionError: log.warn(_('%s, %i: Could not read survey ID, but should be able to.') % (image.filename, image.tiff_page)) failed_pages.add(page) self.duplex_copy_image_attr(failed_pages, "survey_id", _("Could not read survey ID of either %s, %i or %s, %i!")) # Simply use the survey ID from the first image globally self.obj.survey_id = self.obj.images[0].survey_id if self.obj.survey_id != self.obj.survey.survey_id: # Broken survey ID ... log.warn(_("Got a wrong survey ID (%s, %i)! It is %s, but should be %i.") % (self.obj.images[0].filename, self.obj.images[0].tiff_page, self.obj.survey_id, self.obj.survey.survey_id)) self.obj.valid = 0 else: # Assume that the data is from the correct survey self.obj.survey_id = self.obj.survey.survey_id for image in self.obj.images: image.survey_id = self.obj.survey.survey_id # Figure out the questionnaire ID if neccessary # ********************************************* if self.obj.survey.defs.print_questionnaire_id: questionnaire_ids = [] for page, image in enumerate(self.obj.images): try: if not duplex_mode or (image.page_number is not None and image.page_number % 2 == 0): image.recognize.calculate_questionnaire_id() except RecognitionError: log.warn(_('%s, %i: Could not read questionnaire ID, but should be able to.') % \ (image.filename, image.tiff_page)) failed_pages.add(page) if image.questionnaire_id is not None: questionnaire_ids.append(image.questionnaire_id) self.duplex_copy_image_attr(failed_pages, "questionnaire_id", _("Could not read questionnaire ID of either %s, %i or %s, %i!")) if len(questionnaire_ids): self.obj.questionnaire_id = questionnaire_ids[0] else: self.obj.questionnaire_id = self.obj.images[0].questionnaire_id # Try to load the global ID. If it does not exist we will get None, if # it does, then it will be non-None. We don't care much about it # internally anyways. # However, we do want to ensure that it is the same everywhere if it # can be read in. # ********************************************* for page, image in enumerate(self.obj.images): try: if not duplex_mode or (image.page_number is not None and image.page_number % 2 == 0): image.recognize.calculate_global_id() except RecognitionError: pass self.duplex_copy_image_attr(failed_pages, "global_id") self.obj.global_id = self.obj.images[0].global_id for image in self.obj.images: if self.obj.global_id != image.global_id or \ self.obj.survey_id != image.survey_id or \ self.obj.questionnaire_id != image.questionnaire_id: if not warned_multipage_not_correctly_scanned: log.warn(_("Got different IDs on different pages for at least one sheet! Do *NOT* try to use filters with this survey! You have to run a \"reorder\" step for this to work properly!")) warned_multipage_not_correctly_scanned = True # Done if failed_pages: self.obj.valid = 0 def clean(self): for image in self.obj.images: image.recognize.clean() def duplex_copy_image_attr(self, failed_pages, attr, error_msg=None): """If in duplex mode, this function will copy the given attribute from the image that defines it over to the one that does not. ie. if the attribute is None in one and differently in the other image it is copied. """ i = 0 while i < len(self.obj.images): failed = (i in failed_pages or i + 1 in failed_pages) first = self.obj.images[i] second = self.obj.images[i + 1] if getattr(first, attr) is None and getattr(second, attr) is None: if error_msg is not None and not failed: log.warn(error_msg % (first.filename, first.tiff_page, second.filename, second.tiff_page)) elif getattr(first, attr) is None: setattr(first, attr, getattr(second, attr)) elif getattr(second, attr) is None: setattr(second, attr, getattr(first, attr)) i += 2 def get_page_image(self, page_number): img = self.obj.get_page_image(page_number) if self.filter_image is not None: return img if img == self.filter_image else None return img class Image(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'recognize' obj_class = model.sheet.Image def __init__(self, *args): model.buddy.Buddy.__init__(self, *args) if self.obj.sheet.survey.defs.style == "classic": from . import classic elif self.obj.sheet.survey.defs.style == "code128": from . import code128 elif self.obj.sheet.survey.defs.style == "qr": from . import qrcode elif self.obj.sheet.survey.defs.style == "custom": if not hasattr(self.obj, "style"): import sys log.error(_("No style buddy loaded. This needs to be done for the \"custom\" style!")) sys.exit(1) else: raise AssertionError def calculate_rotation(self): if self.obj.ignored: self.obj.rotated = None else: self.obj.rotated = self.obj.style.get_page_rotation() def calculate_page_number(self): if self.obj.ignored: self.obj.page_number = None else: self.obj.page_number = self.obj.style.get_page_number() def calculate_survey_id(self): if self.obj.ignored: self.obj.survey_id = None else: self.obj.survey_id = self.obj.style.get_survey_id() def calculate_questionnaire_id(self): if self.obj.ignored: self.obj.questionnaire_id = None else: self.obj.questionnaire_id = self.obj.style.get_questionnaire_id() def calculate_global_id(self): if self.obj.ignored: self.obj.global_id = None else: self.obj.global_id = self.obj.style.get_global_id() def clean(self): self.obj.surface.clean() def calculate_matrix(self): if self.obj.ignored: self.obj.matrix.set_px_to_mm(None) return try: # Reset matrix, so that we do not use some existing (and broken) # matrix for the resolution estimation. self.obj.matrix.set_px_to_mm(None) matrix = image.calculate_matrix( self.obj.surface.surface, self.obj.matrix.mm_to_px(), defs.corner_mark_left, defs.corner_mark_top, self.obj.sheet.survey.defs.paper_width - defs.corner_mark_left - defs.corner_mark_right, self.obj.sheet.survey.defs.paper_height - defs.corner_mark_top - defs.corner_mark_bottom, ) except AssertionError: self.obj.matrix.set_px_to_mm(None) raise RecognitionError else: self.obj.matrix.set_px_to_mm(matrix) def get_coverage(self, x, y, width, height): assert(not self.obj.ignored) return image.get_coverage( self.obj.surface.surface, self.matrix, x, y, width, height ) def get_masked_coverage(self, mask, x, y): assert(not self.obj.ignored) return image.get_masked_coverage( self.obj.surface.surface, mask, x, y ) def get_masked_coverage_without_lines(self, mask, x, y, line_width, line_count): assert(not self.obj.ignored) return image.get_masked_coverage_without_lines( self.obj.surface.surface, mask, x, y, line_width, line_count ) def get_masked_white_area_count(self, mask, x, y, min_size, max_size): assert(not self.obj.ignored) return image.get_masked_white_area_count( self.obj.surface.surface, mask, x, y, min_size, max_size ) def correction_matrix_masked(self, x, y, mask): assert(not self.obj.ignored) return image.calculate_correction_matrix_masked( self.obj.surface.surface, mask, self.matrix, x, y ) def find_box_corners(self, x, y, width, height): assert(not self.obj.ignored) tl, tr, br, bl = image.find_box_corners( self.obj.surface.surface, self.matrix, x, y, width, height) tolerance = defs.find_box_corners_tolerance if(abs(x - tl[0]) > tolerance or abs(y - tl[1]) > tolerance or abs(x + width - tr[0]) > tolerance or abs(y - tr[1]) > tolerance or abs(x + width - br[0]) > tolerance or abs(y + height - br[1]) > tolerance or abs(x - bl[0]) > tolerance or abs(y + height - bl[1]) > tolerance ): raise AssertionError("The found values differ too much from where the box should be.") return tl, tr, br, bl @property def matrix(self): return self.obj.matrix.mm_to_px(fallback=False) class Questionnaire(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'recognize' obj_class = model.questionnaire.Questionnaire def identify(self, clean=True): # recognize image try: self.obj.sheet.recognize.recognize() result = True # Mark sheet as invalid if any page is missing, for page in range(self.obj.page_count): img = self.obj.sheet.get_page_image(page + 1) if img is None or img.recognize.matrix is None: self.obj.sheet.valid = False except RecognitionError: self.obj.sheet.quality = 0 result = False # clean up if clean: self.obj.sheet.recognize.clean() return result def recognize(self, skip_identify=False, image=None): # recognize image if not skip_identify: assert image is None res = self.identify(clean=False) elif image is None: for img in self.obj.images: if not img.ignored: img.surface.load() res = True else: image.surface.load() res = True if res: # iterate over qobjects self.obj.sheet.recognize.filter_image = image for qobject in self.obj.qobjects: qobject.recognize.recognize() self.obj.sheet.recognize.filter_image = None quality = 1 for qobject in self.obj.qobjects: quality = min(quality, qobject.recognize.get_quality()) self.obj.sheet.quality = quality # Mark the image as "recognized". It might have failed, but even if that # happened, we don't want to retry all the time. self.obj.sheet.recognized = True # Any newly recognized sheet is definately not verified. # This is relevant for reruns. for img in self.obj.sheet.images: img.verified = False # clean up self.obj.sheet.recognize.clean() class QObject(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'recognize' obj_class = model.questionnaire.QObject def recognize(self): pass def get_quality(self): return 1 class Question(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'recognize' obj_class = model.questionnaire.Question def recognize(self): # iterate over boxes for box in self.obj.boxes: box.recognize.recognize() def get_quality(self): result = 1 for box in self.obj.boxes: result = min(result, box.data.quality) return result class Box(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'recognize' obj_class = model.questionnaire.Box def recognize(self): pass class Checkbox(Box, metaclass=model.buddy.Register): name = 'recognize' obj_class = model.questionnaire.Checkbox def prepare_mask(self): img = self.obj.sheet.recognize.get_page_image(self.obj.page_number) width, height = self.obj.width, self.obj.height line_width = self.obj.lw matrix = list(img.recognize.matrix) # Remove any offset from the matrix matrix[4] = 0 matrix[5] = 0 matrix = cairo.Matrix(*matrix) px_width, px_height = matrix.transform_distance(width, height) px_width, px_height = int(math.ceil(px_width)), int(math.ceil(px_height)) surf = cairo.ImageSurface(cairo.FORMAT_A1, px_width, px_height) cr = cairo.Context(surf) cr.set_source_rgba(0, 0, 0, 0) cr.set_operator(cairo.OPERATOR_SOURCE) cr.paint() # Move to center and apply matrix cr.translate(0.5 * px_width, 0.5 * px_height) cr.transform(matrix) cr.set_source_rgba(0, 0, 0, 1) cr.set_line_width(line_width) matrix.invert() xoff, yoff = matrix.transform_distance(px_width / 2.0, px_height / 2.0) xoff = xoff - width / 2 yoff = yoff - height / 2 return cr, surf, line_width, width, height, xoff, yoff def get_outline_mask(self): cr, surf, line_width, width, height, xoff, yoff = self.prepare_mask() if self.obj.form == "ellipse": cr.save() cr.scale((width - line_width) / 2.0, (height - line_width) / 2.0) cr.arc(0, 0, 1.0, 0, 2*math.pi) # Restore old matrix (without removing the current path) cr.restore() else: cr.translate(-0.5 * width, -0.5 * height) cr.rectangle(line_width / 2, line_width / 2, width - line_width / 2, height - line_width / 2) cr.stroke() surf.flush() del cr return surf, xoff, yoff def get_inner_mask(self): """Note this discards half a line width inside the box!""" cr, surf, line_width, width, height, xoff, yoff = self.prepare_mask() if self.obj.form == "ellipse": cr.save() cr.scale((width - 3*line_width) / 2.0, (height - 3*line_width) / 2.0) cr.arc(0, 0, 1.0, 0, 2*math.pi) # Restore old matrix (without removing the current path) cr.restore() else: cr.translate(-0.5 * width, -0.5 * height) cr.rectangle(1.5 * line_width, 1.5 * line_width, width - 3 * line_width, height - 3 * line_width) cr.fill() surf.flush() del cr return surf, xoff, yoff def recognize(self): img = self.obj.sheet.recognize.get_page_image(self.obj.page_number) if img is None or img.recognize.matrix is None: return surf, xoff, yoff = self.get_outline_mask() matrix, covered = img.recognize.correction_matrix_masked( self.obj.x, self.obj.y, surf ) # Calculate some sort of quality for the checkbox position if covered < defs.image_line_coverage: pos_quality = 0 else: pos_quality = min(covered + 0.2, 1) x, y = matrix.transform_point(self.obj.x, self.obj.y) width, height = matrix.transform_distance(self.obj.width, self.obj.height) self.obj.data.x = x + xoff self.obj.data.y = y + yoff self.obj.data.width = width self.obj.data.height = height # The debug struct will be filled in if debugging is enabled in the # C library. This is done by the boxgallery script currently. self.debug = {} mask, xoff, yoff = self.get_inner_mask() x, y = self.obj.data.x, self.obj.data.y x, y = x + xoff, y + yoff x, y = img.recognize.matrix.transform_point(x, y) x, y = int(x), int(y) # This is not the outline, but the width of the drawn stroke! remove_line_width = 1.2 * pt_to_mm remove_line_width_px = max(img.recognize.matrix.transform_distance(remove_line_width, remove_line_width)) coverage = img.recognize.get_masked_coverage(mask, x, y) self.obj.data.metrics['coverage'] = coverage self.debug['coverage'] = image.get_debug_surface() # Remove 3 lines with width 1.2pt(about 5px). coverage = img.recognize.get_masked_coverage_without_lines(mask, x, y, remove_line_width_px, 3) self.obj.data.metrics['cov-lines-removed'] = coverage self.debug['cov-lines-removed'] = image.get_debug_surface() count, coverage = img.recognize.get_masked_white_area_count(mask, x, y, 0.05, 1.0) self.obj.data.metrics['cov-min-size'] = coverage self.debug['cov-min-size'] = image.get_debug_surface() state = 0 quality = -1 # Iterate the ranges for metric, value in self.obj.data.metrics.items(): metric = defs.checkbox_metrics[self.obj.sheet.survey.defs.checkmode][metric] for lower, upper in zip(metric[:-1], metric[1:]): if value >= lower[0] and value <= upper[0]: # Interpolate quality value if lower[0] != upper[0]: metric_quality = lower[2] + (upper[2] - lower[2]) * (value - lower[0]) / (upper[0] - lower[0]) else: metric_quality = lower[2] if metric_quality > quality: state = lower[1] quality = metric_quality self.obj.data.state = state self.obj.data.quality = min(quality, pos_quality) class Textbox(Box, metaclass=model.buddy.Register): name = 'recognize' obj_class = model.questionnaire.Textbox def recognize(self): class Quadrilateral(): """This class iterates through small box areas in a quadriliteral. This is usefull because some scanners have trapezoidal distortions.""" # Assumes top left, top right, bottom right, bottom left # corner. def __init__(self, p0, p1, p2, p3): self.x0 = p0[0] self.y0 = p0[1] self.x1 = p1[0] self.y1 = p1[1] self.x2 = p2[0] self.y2 = p2[1] self.x3 = p3[0] self.y3 = p3[1] # 0 -> 1 self.m0 = (self.y1 - self.y0) / (self.x1 - self.x0) self.m1 = (self.x2 - self.x1) / (self.y2 - self.y1) self.m2 = (self.y3 - self.y2) / (self.x3 - self.x2) self.m3 = (self.x0 - self.x3) / (self.y0 - self.y3) self.top = min(self.y0, self.y1) self.bottom = max(self.y2, self.y3) self.left = min(self.x0, self.x3) self.right = max(self.x1, self.x2) def iterate_bb(self, step_x, step_y, test_width, test_height, padding): y = self.top while y + test_height < self.bottom: x = self.left while x + test_width < self.right: yield x, y x += step_x y += step_y def iterate_outline(self, step_x, step_y, test_width, test_height, padding): # Top x, y = self.x0, self.y0 x += padding y += padding dest_x = self.x1 - padding - test_width dest_y = self.y1 + padding dist_x = dest_x - x dist_y = dest_y - y length = math.sqrt(dist_x ** 2 + dist_y ** 2) for step in range(int(length / step_x)): yield x + dist_x * step / (length / step_x), y + dist_y * step / (length / step_x) yield dest_x, dest_y # Bottom x, y = self.x3, self.y3 x = x + padding y = y - padding - test_height dest_x = self.x2 - padding - test_width dest_y = self.y2 - padding - test_height dist_x = dest_x - x dist_y = dest_y - y length = math.sqrt(dist_x ** 2 + dist_y ** 2) for step in range(int(length / step_x)): yield x + dist_x * step / (length / step_x), y + dist_y * step / (length / step_x) yield dest_x, dest_y # Left x, y = self.x0, self.y0 x += padding y += padding dest_x = self.x3 + padding dest_y = self.y3 - padding - test_height dist_x = dest_x - x dist_y = dest_y - y length = math.sqrt(dist_x ** 2 + dist_y ** 2) for step in range(int(length / step_y)): yield x + dist_x * step / (length / step_y), y + dist_y * step / (length / step_y) yield dest_x, dest_y # Right x, y = self.x1, self.y1 x = x - padding - test_width y = y + padding dest_x = self.x2 - padding - test_width dest_y = self.y2 - padding - test_height dist_x = dest_x - x dist_y = dest_y - y length = math.sqrt(dist_x ** 2 + dist_y ** 2) for step in range(int(length / step_y)): yield x + dist_x * step / (length / step_y), y + dist_y * step / (length / step_y) yield dest_x, dest_y def iterate(self, step_x, step_y, test_width, test_height, padding): for x, y in self.iterate_bb(step_x, step_y, test_width, test_height, padding): ly = self.y0 + self.m0 * (x - self.x0) if not ly + padding < y: continue ly = self.y2 + self.m2 * (x - self.x2) if not ly - padding > y + test_height: continue lx = self.x1 + self.m1 * (y - self.y1) if not lx - padding > x + test_width: continue lx = self.x3 + self.m3 * (y - self.y3) if not lx + padding < x: continue yield x, y for x, y in self.iterate_outline(step_x, step_y, test_width, test_height, padding): yield x, y bbox = None img = self.obj.sheet.recognize.get_page_image(self.obj.page_number) if img is None or img.recognize.matrix is None: return x = self.obj.x y = self.obj.y width = self.obj.width height = self.obj.height # Scanning area and stepping step_x = defs.textbox_scan_step_x step_y = defs.textbox_scan_step_x test_width = defs.textbox_scan_width test_height = defs.textbox_scan_height # extra_padding is always added to the box side at the end. extra_padding = defs.textbox_extra_padding scan_padding = defs.textbox_scan_uncorrected_padding quad = Quadrilateral((x, y), (x + width, y), (x + width, y + height), (x, y + height)) try: quad = Quadrilateral(*img.recognize.find_box_corners(x, y, width, height)) # Lower padding, as we found the corners and are therefore more acurate scan_padding = defs.textbox_scan_padding except AssertionError: pass surface = img.surface.surface matrix = img.recognize.matrix for x, y in quad.iterate(step_x, step_y, test_width, test_height, scan_padding): # Use the image module directly as we are calling in *a lot* coverage = image.get_coverage(surface, matrix, x, y, test_width, test_height) if coverage > defs.textbox_scan_coverage: if not bbox: bbox = [x, y, test_width, test_height] else: bbox_x = min(bbox[0], x) bbox_y = min(bbox[1], y) bbox[2] = max(bbox[0] + bbox[2], x + test_width) - bbox_x bbox[3] = max(bbox[1] + bbox[3], y + test_height) - bbox_y bbox[0] = bbox_x bbox[1] = bbox_y if bbox and (bbox[2] > defs.textbox_minimum_writing_width or bbox[3] > defs.textbox_minimum_writing_height): # Do not accept very small bounding boxes. self.obj.data.state = True self.obj.data.x = bbox[0] - (scan_padding + extra_padding) self.obj.data.y = bbox[1] - (scan_padding + extra_padding) self.obj.data.width = bbox[2] + 2 * (scan_padding + extra_padding) self.obj.data.height = bbox[3] + 2 * (scan_padding + extra_padding) else: self.obj.data.state = False self.obj.data.x = self.obj.x self.obj.data.y = self.obj.y self.obj.data.width = self.obj.width self.obj.data.height = self.obj.height class Codebox(Textbox, metaclass=model.buddy.Register): name = 'recognize' obj_class = model.questionnaire.Codebox def recognize(self): img = self.obj.sheet.recognize.get_page_image(self.obj.page_number) if img is None or img.recognize.matrix is None: return x = self.obj.x y = self.obj.y width = self.obj.width height = self.obj.height surface = img.surface.surface matrix = img.recognize.matrix res = read_barcode(surface, matrix, x, y, width, height, "QRCODE") # This is maybe a bit odd, but we accept empty string as a valid # content (if there was a barcode which was just the empty string). if res is not None: self.obj.data.state = True self.obj.data.text = res else: self.obj.data.state = False self.obj.data.text = None sdaps-1.9.8/sdaps/recognize/classic.py0000644000175000000660000001271013367301321020471 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008,2011, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from sdaps import defs from sdaps import model from sdaps.utils.exceptions import RecognitionError from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext # Note, while it is possible to cache data in the image object, this data # will not change when the image is switched to the next sheet. So one needs # to be careful when to invalidate it. # All of these functions can assume that the matrix has been recognized # for the image. # They may throw a RecognitionError if there was an unrecoverable error. # If no data can be retrieved(because eg. it is not printed on that # page) they may return None to indicate this. class Image(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'style' obj_class = model.sheet.Image def get_page_rotation(self): # Returns page rotation or "None" if it cannot be retrieved res = get_pagenumber_and_rotation(self) if res is None: return None return res[0] def get_page_number(self): # Returns page number or "None" if it cannot be retrieved # Returns page number rotation or "None" if it cannot be retrieved res = get_pagenumber_and_rotation(self) if res is None: return None # The page may not be rotated at this point if res[0]: raise RecognitionError return res[1] def get_survey_id(self): # Returns the survey ID or "None" if it cannot be retrieved if self.obj.page_number % 2 == 0 or \ self.obj.sheet.survey.questionnaire.page_count == 1: pos = self.obj.sheet.survey.defs.get_survey_id_pos() survey_id = read_codebox(self, pos[0], pos[2]) survey_id = read_codebox(self, pos[1], pos[2], survey_id) return survey_id else: return None def get_questionnaire_id(self): # Returns the questionnaire ID or "None" if it cannot be retrieved if self.obj.page_number % 2 == 0 or \ self.obj.sheet.survey.questionnaire.page_count == 1: pos = self.obj.sheet.survey.defs.get_questionnaire_id_pos() questionnaire_id = read_codebox(self, pos[0], pos[2]) return questionnaire_id else: return None def get_global_id(self): # The classic style does not support a global ID property. return None ############################ # Internal Helpers ############################ def read_codebox(self, x, y, code=0): for i in range(defs.codebox_length): code <<= 1 coverage = self.obj.recognize.get_coverage( x + (i * defs.codebox_step) + defs.codebox_offset, y + defs.codebox_offset, defs.codebox_step - 2 * defs.codebox_offset, defs.codebox_height - 2 * defs.codebox_offset ) if coverage > defs.codebox_on_coverage: code += 1 return code def get_pagenumber_and_rotation(self): # The coordinates in defs are the center of the line, not the bounding box of the box ... # Its a bug im stamp # So we need to adjust them half_pt = 0.5 / 72.0 * 25.4 pt = 1.0 / 72.0 * 25.4 # Check whether there is a valid transformation matrix. If not simply return. if self.obj.matrix.mm_to_px(False) is None: return width = defs.corner_box_width height = defs.corner_box_height padding = defs.corner_box_padding survey = self.obj.sheet.survey corner_boxes_positions = [ (defs.corner_mark_left + padding, defs.corner_mark_top + padding), (survey.defs.paper_width - defs.corner_mark_right - padding - width, defs.corner_mark_top + padding), (defs.corner_mark_left + padding, survey.defs.paper_height - defs.corner_mark_bottom - padding - height), (survey.defs.paper_width - defs.corner_mark_right - padding - width, survey.defs.paper_height - defs.corner_mark_bottom - padding - height) ] corners = [ int(self.obj.recognize.get_coverage( corner[0] - half_pt, corner[1] - half_pt, width + pt, height + pt ) > defs.cornerbox_on_coverage) for corner in corner_boxes_positions ] try: page_number = defs.corner_boxes.index(corners) + 1 rotated = False except ValueError: try: page_number = defs.corner_boxes.index(corners[::-1]) + 1 rotated = True except ValueError: raise RecognitionError return rotated, page_number sdaps-1.9.8/sdaps/recognize/code128.py0000644000175000000660000001441313367301321020217 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2012 Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from sdaps import defs from sdaps import model from sdaps.utils.exceptions import RecognitionError from sdaps.utils.barcode import read_barcode # Reading the metainformation of CODE-128 style questionnaires. See classic.py # for some more information. class Image(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'style' obj_class = model.sheet.Image def get_page_rotation(self): # Returns page rotation or "None" if it cannot be retrieved # Figure out wether the page is rotated by looking for a barcode first # at the bottom right, then at the top left. # Note that we do not care about the value of the barcode, we are happy # to simply know that it exists. paper_width = self.obj.sheet.survey.defs.paper_width paper_height = self.obj.sheet.survey.defs.paper_height # Search for the barcode in the lower right corner. # Note that we cannot find another barcode this way, because the one in the # center of the page is not complete code = \ read_barcode(self.obj.surface.surface, self.obj.matrix.mm_to_px(), paper_width / 2, paper_height - defs.corner_mark_bottom - defs.code128_vpad - defs.code128_height - 5, paper_width / 2, defs.corner_mark_bottom + defs.code128_vpad + defs.code128_height + 5) if code is None: # Well, that failed, so try to search the upper left corner instead code = \ read_barcode(self.obj.surface.surface, self.obj.matrix.mm_to_px(), 0, 0, paper_width / 2, defs.corner_mark_bottom + defs.code128_vpad + defs.code128_height + 5) if code is not None: return True else: return None else: return False def get_page_number(self): # Returns page number or "None" if it cannot be retrieved # In this function assume that the rotation is correct already. paper_width = self.obj.sheet.survey.defs.paper_width paper_height = self.obj.sheet.survey.defs.paper_height # Search for the barcode in the lower right corner. code = \ read_barcode(self.obj.surface.surface, self.obj.matrix.mm_to_px(), paper_width / 2, paper_height - defs.corner_mark_bottom - defs.code128_vpad - defs.code128_height - 5, paper_width / 2, defs.corner_mark_bottom + defs.code128_vpad + defs.code128_height + 5) # The code needs to be entirely numeric and at least 4 characters for the page if code is None or(not code.isdigit() and len(code) < 4): return None # The page number is in the lower four digits, simply extract it and convert # to integer return int(code[-4:]) def get_survey_id(self): # Returns the survey ID or "None" if it cannot be retrieved # In this function assume that the rotation is correct already. paper_width = self.obj.sheet.survey.defs.paper_width paper_height = self.obj.sheet.survey.defs.paper_height # Search for the barcode in the lower left corner. code = \ read_barcode(self.obj.surface.surface, self.obj.matrix.mm_to_px(), paper_width / 2, paper_height - defs.corner_mark_bottom - defs.code128_vpad - defs.code128_height - 5, paper_width / 2, defs.corner_mark_bottom + defs.code128_vpad + defs.code128_height + 5) if code is None or not code.isdigit() or len(code) <= 4: return None return int(code[:-4]) def get_questionnaire_id(self): # Returns the questionnaire ID or "None" if it cannot be retrieved # In this function assume that the rotation is correct already. paper_width = self.obj.sheet.survey.defs.paper_width paper_height = self.obj.sheet.survey.defs.paper_height # Search for the barcode on the bottom left of the page code = \ read_barcode(self.obj.surface.surface, self.obj.matrix.mm_to_px(), 0, paper_height - defs.corner_mark_bottom - defs.code128_vpad - defs.code128_height - 5, paper_width / 2, defs.corner_mark_bottom + defs.code128_vpad + defs.code128_height + 5) # Simply return the code, it may be alphanumeric, we don't care here # XXX: Is that assumption sane? return code def get_global_id(self): # Returns the global ID or "None" if it cannot be retrieved # In this function assume that the rotation is correct already. paper_width = self.obj.sheet.survey.defs.paper_width paper_height = self.obj.sheet.survey.defs.paper_height # Search for the barcode in the bottom center of the page code = \ read_barcode(self.obj.surface.surface, self.obj.matrix.mm_to_px(), paper_width / 4, paper_height - defs.corner_mark_bottom - defs.code128_vpad - defs.code128_height - 5, paper_width / 2, defs.corner_mark_bottom + defs.code128_vpad + defs.code128_height + 5) # Simply return the code, it may be alphanumeric, we don't care here return code sdaps-1.9.8/sdaps/recognize/qrcode.py0000644000175000000660000000701213423060331020320 0ustar benjaminlock00000000000000# SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2014, Michael Batchelor # Copyright(C) 2014, Chuck Collins # Copyright(C) 2014, Jacob Green # Copyright(C) 2014, Dustin Ngo # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from sdaps import defs from sdaps import model from sdaps.utils.exceptions import RecognitionError from sdaps.utils.barcode import read_barcode class Image(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'style' obj_class = model.sheet.Image def get_page_rotation(self): code = self.find_bottom_right_barcode() if code is None: # Well, that failed, so try to search the upper left corner instead code = self.find_top_left_barcode() if code is not None: return True else: return None else: return False def get_page_number(self): code = self.find_bottom_right_barcode() if code is None or (not code.isdigit() and len(code) < 4): return None return int(code[-4:]) def get_survey_id(self): code = self.find_bottom_right_barcode() if code is None or not code.isdigit() or len(code) <= 4: return None return int(code[:-4]) def get_questionnaire_id(self): return self.find_bottom_left_barcode() def get_global_id(self): return self.find_bottom_center_barcode() def find_bottom_right_barcode(self): return read_barcode(self.obj.surface.surface, self.obj.matrix.mm_to_px(), self.paper_width() * 0.75, self.paper_height() * 0.75, self.paper_width() * 0.25, self.paper_height() * 0.25, "QRCODE") def find_top_left_barcode(self): return read_barcode(self.obj.surface.surface, self.obj.matrix.mm_to_px(), 0, 0, self.paper_width() * 0.25, self.paper_height() * 0.25, "QRCODE") def find_bottom_left_barcode(self): return read_barcode(self.obj.surface.surface, self.obj.matrix.mm_to_px(), 0, self.paper_height() * 0.75, self.paper_width() * 0.25, self.paper_height() * 0.25, "QRCODE") def find_bottom_center_barcode(self): return read_barcode(self.obj.surface.surface, self.obj.matrix.mm_to_px(), self.paper_width() * 0.375, self.paper_height() * 0.75, self.paper_width() * 0.25, self.paper_height() * 0.25, "QRCODE") def paper_width(self): return self.obj.sheet.survey.defs.paper_width def paper_height(self): return self.obj.sheet.survey.defs.paper_height sdaps-1.9.8/sdaps/reorder/0000755000175000000660000000000013611127124016151 5ustar benjaminlock00000000000000sdaps-1.9.8/sdaps/reorder/__init__.py0000644000175000000660000000656413473755104020310 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2012, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """ This module reorders already recognized data according to the questionnaire IDs. """ from collections import defaultdict from sdaps import model from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext def reorder(survey): """We can assume quite some things in this function, because recognize properly handles it. ie. * Every image will be tagged correctly (as long as the data is known) * in duplex mode both the front/back image will be tagged, so we don't need to care about that here! """ image_count = survey.questionnaire.page_count # We have two images per page in simplex mode! if not survey.defs.duplex: image_count = image_count * 2 # First, go over all sheets and figure out which ones need reordering. # For every sheet that isn't quite right, we extract the images, and delete # the sheet. # The images are put into a dictionnary using the questionnaire ID. # Each entry in the dictionary is a list. images = defaultdict(lambda : []) # Load all sheets into memory sheets = [] survey.iterate(lambda: sheets.append(survey.get_sheet())) for sheet in sheets: # Use a flat copy to iterate over broken = False pages = set() for image in sheet.images: if sheet.questionnaire_id != image.questionnaire_id: broken = True if sheet.global_id != image.global_id: broken = True # Check that no page exists twice if image.page_number is not None and image.page_number in pages: broken = True pages.add(image.page_number) # Also consider incomplete sets broken, so that hopefully they will # be filled up with the correct page. if len(sheet.images) != image_count: broken = True if broken: # Drop from the list of sheets survey.delete_sheet(sheet) for image in sheet.images: images[(image.questionnaire_id, image.global_id)].append(image) # We have dictionnary of lists of images that needs to be put into sheets # again. # This could probably be more robust. We don't care about the questionnaire # ID itself here, just put each list into sheets, splitting it into many # if there are too many images. for img_list in images.values(): while len(img_list) > 0: sheet = model.sheet.Sheet() survey.add_sheet(sheet) while len(img_list) > 0 and len(sheet.images) < image_count: sheet.add_image(img_list.pop(0)) survey.save() sdaps-1.9.8/sdaps/report/0000755000175000000660000000000013611127124016022 5ustar benjaminlock00000000000000sdaps-1.9.8/sdaps/report/__init__.py0000644000175000000660000000670313367301321020142 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """ This modules contains the functionality to create PDF based reports. """ import os from reportlab import platypus from sdaps import model from sdaps import clifilter from sdaps import template from sdaps import matrix from sdaps.utils import paper from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext from . import buddies def report(survey, filter, filename=None, papersize=None, small=0, suppress=None): assert isinstance(survey, model.survey.Survey) # compile clifilter filter = clifilter.clifilter(survey, filter) # First: calculate buddies # init buddies survey.questionnaire.calculate.init() # iterate over sheets survey.iterate( survey.questionnaire.calculate.read, lambda: survey.sheet.valid and not survey.sheet.empty and filter() ) # do calculations survey.questionnaire.calculate.calculate() # Second: report buddies # init buddies survey.questionnaire.report.init(small, suppress) # iterate over sheets survey.iterate( survey.questionnaire.report.report, lambda: survey.sheet.valid and filter() ) # create story story = template.story_title( survey, { _('Turned in Questionnaires'): survey.questionnaire.calculate.count, } ) story.extend(survey.questionnaire.report.story()) # create report(out of story) if filename is None: filename = survey.new_path('report_%i.pdf') subject = [] for key, value in survey.info.items(): subject.append('%(key)s: %(value)s' % {'key': key, 'value': value}) subject = '\n'.join(subject) papersize = paper.get_reportlab_papersize(papersize) doc = template.DocTemplate( filename, _('sdaps report'), { 'title': survey.title, 'subject': subject, }, papersize=papersize ) doc.build(story) def stats(survey, filter, filename=None, small=0, suppress=None): if filename is None: filename = survey.new_path('report_%i.pdf') # do a report report(survey, filter, filename=filename, small=small) # save reference (to highlight large differences) survey.questionnaire.calculate.reference() # do a report for every filter for i, subfilter in enumerate(survey.questionnaire.report.filters()): if filter is None: filt = subfilter else: filt = "(%s) and (%s)" % (filter, subfilter) report( survey, filt, filename='%s_%i %s.pdf' % (filename.split('.')[0], i, subfilter), small=small, suppress=suppress) sdaps-1.9.8/sdaps/report/answers.py0000644000175000000660000002753213367301321020070 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import io from PIL import Image from reportlab import pdfgen from reportlab import platypus from reportlab.lib import styles from reportlab.lib import units from reportlab.lib import pagesizes from reportlab.lib import enums from reportlab.lib import colors from xml.sax.saxutils import escape from sdaps import template from sdaps import model from sdaps import image from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext from . import flowables mm = units.mm stylesheet = dict(template.stylesheet) stylesheet['Right'] = styles.ParagraphStyle( 'Right', parent=stylesheet['Normal'], alignment=enums.TA_RIGHT, ) stylesheet['Right_Highlight'] = styles.ParagraphStyle( 'Right_Highlight', parent=stylesheet['Right'], textColor=colors.Color(255, 0, 0) ) stylesheet['Normal_Highlight'] = styles.ParagraphStyle( 'Normal_Highlight', parent=stylesheet['Normal'], textColor=colors.Color(255, 0, 0) ) class Choice(platypus.Flowable): '''One answer of a choice ''' box_width = 200 box_height = 9 box_depth = 5 box_margin = 1 value_width = 45 gap = 6 def __init__(self, answer, value, significant=0): platypus.Flowable.__init__(self) if significant: stylesheet_name = 'Right_Highlight' else: stylesheet_name = 'Right' self.answer = platypus.Paragraph(escape(answer), stylesheet[stylesheet_name]) self.value = platypus.Paragraph( '%.2f %%' % (value * 100), stylesheet[stylesheet_name] ) self.black_box = flowables.Box( value * self.box_width, self.box_height, self.box_depth, self.box_margin ) self.black_box.transparent = 0 self.black_box.fill = 1 self.black_box.fill_color = (0.6, 0.6, 0.6) self.white_box = flowables.Box( (1 - value) * self.box_width, self.box_height, self.box_depth, self.box_margin ) def wrap(self, available_width, available_height): self.width = available_width self.white_box.wrap(available_width, available_height) available_width -= self.white_box.width - self.white_box.cx self.black_box.wrap(available_width, available_height) available_width -= self.black_box.width available_width -= self.gap self.value.wrap(self.value_width, available_height) available_width -= self.value.width self.answer.wrap(available_width, available_height) self.height = max( self.answer.height, self.value.height, self.black_box.height + self.box_margin, self.white_box.height + self.box_margin ) return self.width, self.height def draw(self): if 0: assert isinstance(self.canv, pdfgen.canvas.Canvas) self.answer.drawOn( self.canv, 0, self.height / 2.0 - self.answer.height / 2.0 ) self.value.drawOn( self.canv, self.answer.width, self.height / 2.0 - self.value.height / 2.0 ) self.black_box.drawOn( self.canv, self.answer.width + self.value.width + self.gap, self.height / 2.0 - self.black_box.height / 2.0 ) self.white_box.drawOn( self.canv, self.answer.width + self.value.width + self.gap + self.black_box.width - self.black_box.cx, self.height / 2.0 - self.white_box.height / 2.0 ) class Range(platypus.Flowable): ''' ----- self.top_margin values(percent) self.values_height ----- self.values_gap values(bars) self.bars_height ----- skala with mean self.skala_height ----- marks(1 - range) self.marks_height ----- ''' margin = 6 top_margin = 0 left_margin = 12 def __init__(self, range_min, range_max, values, answers, mean, standard_deviation, count, significant=0): platypus.Flowable.__init__(self) self.range_min = range_min self.range_max = range_max self.values = values self.mean = mean self.standard_deviation = standard_deviation self.count = count self.box_width = 40 self.box_height = 60 self.box_depth = 6 self.mean_width = 2 self.mean_height = 6 self.values_height = 10 self.values_gap = self.box_depth self.bars_height = max(self.values.values()) * self.box_height self.skala_height = self.mean_height self.marks_height = 10 if significant: stylesheet_name = 'Normal_Highlight' else: stylesheet_name = 'Normal' self.answers_paragraph = \ platypus.Paragraph(escape(' - '.join(answers)), stylesheet[stylesheet_name]) self.count_paragraph = \ platypus.Paragraph(_('Answers: %i') % self.count, stylesheet['Normal']) self.mean_paragraph = \ platypus.Paragraph(_('Mean: %.2f') % self.mean, stylesheet['Normal']) self.stdd_paragraph = \ platypus.Paragraph(_('Standard Deviation: %.2f') % self.standard_deviation, stylesheet['Normal']) def wrap(self, available_width, available_height): self.answers_paragraph.wrap(available_width, available_height) self.count_paragraph.wrap(available_width, available_height) self.mean_paragraph.wrap(available_width, available_height) self.stdd_paragraph.wrap(available_width, available_height) self.width = available_width # self.box_width * 5 self.offset = self.width - self.box_width * len(self.values) - self.margin self.height = self.top_margin + self.values_height + self.values_gap + \ self.bars_height + self.skala_height + self.marks_height return self.width, self.height def draw(self): if 0: assert isinstance(self.canv, pdfgen.canvas.Canvas) self.canv.setFont("Times-Roman", 10) # mean mean = flowables.Box(self.mean_width, self.mean_height, self.box_depth) mean.transparent = 0 mean.fill = 1 mean.fill_color = (0.6, 0.6, 0.6) mean.drawOn(self.canv, self.offset + (self.mean - 0.5) * self.box_width - self.mean_width / 2.0, self.marks_height) # values for i, key in enumerate(range(self.range_min, self.range_max + 1)): if key in self.values: self.canv.drawCentredString( self.offset + (i + 0.5) * self.box_width + self.box_depth * 0.5, self.marks_height + self.skala_height + self.bars_height + self.values_gap, '%.2f %%' % (self.values[key] * 100) ) # bars for i, key in enumerate(range(self.range_min, self.range_max + 1)): if key in self.values: value = self.values[key] else: value = 0 box = flowables.Box(self.box_width, value * self.box_height, self.box_depth) box.transparent = 0 box.fill = 1 box.fill_color = (0.6, 0.6, 0.6) box.drawOn(self.canv, self.offset + i * self.box_width, self.marks_height + self.skala_height) # skala for i in range((self.range_max - self.range_min) * 10 + 1): if i % 10 == 0: self.canv.setLineWidth(0.2) self.canv.line( self.offset + (i / 10.0 + 0.5) * self.box_width, 1 + self.marks_height, self.offset + (i / 10.0 + 0.5) * self.box_width, 5 + self.marks_height ) elif i % 5 == 0: self.canv.line( self.offset + (i / 10.0 + 0.5) * self.box_width, 1.5 + self.marks_height, self.offset + (i / 10.0 + 0.5) * self.box_width, 4.5 + self.marks_height ) else: self.canv.line( self.offset + (i / 10.0 + 0.5) * self.box_width, 2 + self.marks_height, self.offset + (i / 10.0 + 0.5) * self.box_width, 4 + self.marks_height ) if i % 10 == 0: self.canv.setLineWidth(0.1) # marks for i in range(1, len(self.values)+1): self.canv.drawCentredString( self.offset + (i - 0.5) * self.box_width, 0, '%i' % i ) # statistics y_pos = self.marks_height + self.skala_height + self.bars_height + \ self.values_gap + self.values_height self.answers_paragraph.drawOn(self.canv, self.left_margin, y_pos - 15) self.count_paragraph.drawOn(self.canv, self.left_margin, y_pos - 27) self.mean_paragraph.drawOn(self.canv, self.left_margin, y_pos - 39) self.stdd_paragraph.drawOn(self.canv, self.left_margin, y_pos - 51) class Freeform(platypus.Flowable): cache = dict() def __init__(self, box): platypus.Flowable.__init__(self) assert isinstance(box, model.questionnaire.Textbox) assert box.data.state image = box.sheet.get_page_image(box.question.page_number) self.filename = box.question.questionnaire.survey.path(image.filename) self.tiff_page = image.tiff_page self.rotated = image.rotated mm_to_px = image.matrix.mm_to_px() x0, y0 = mm_to_px.transform_point(box.data.x, box.data.y) x1, y1 = mm_to_px.transform_point(box.data.x + box.data.width, box.data.y + box.data.height) self.bbox = (int(x0), int(y0), int(x1), int(y1)) self.width = box.data.width * mm self.height = box.data.height * mm def wrap(self, available_width, available_height): self.available_width = available_width return self.available_width, self.height def draw(self): if 0: assert isinstance(self.canv, pdfgen.canvas.Canvas) if(self.filename, self.tiff_page, self.bbox) in self.cache: img = self.cache[(self.filename, self.tiff_page, self.bbox)] else: img = io.BytesIO(image.get_pbm( image.get_a1_from_tiff( self.filename, self.tiff_page, self.rotated if self.rotated else False ) )) img = Image.open(img).crop(self.bbox) self.cache[(self.filename, self.bbox)] = img self.canv.drawInlineImage(img, 0, 0, self.width, self.height) self.canv.setStrokeColorRGB(0.6, 0.6, 0.6) self.canv.line(0, 0, self.available_width, 0) self.canv.line(0, self.height, self.available_width, self.height) class RawText(platypus.Paragraph): def __init__(self, text, *args, **kwargs): # Replace things like text = escape(text) text = text.replace('\n', '
') text = text platypus.Paragraph.__init__(self, text, *args, bulletText='•', **kwargs) sdaps-1.9.8/sdaps/report/buddies.py0000644000175000000660000002127413375076020020026 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import math from reportlab import platypus from reportlab.lib import styles from reportlab.lib import colors from reportlab.lib import units from sdaps import clifilter from sdaps import template from sdaps import model from xml.sax.saxutils import escape from . import flowables from . import answers from sdaps import calculate mm = units.mm stylesheet = dict(template.stylesheet) stylesheet['Head'] = styles.ParagraphStyle( 'Head', stylesheet['Normal'], fontSize=12, leading=17, backColor=colors.lightgrey, spaceBefore=5 * mm, ) stylesheet['Question'] = styles.ParagraphStyle( 'Question', stylesheet['Normal'], spaceBefore=3 * mm, fontName='Times-Bold', ) stylesheet['Text'] = styles.ParagraphStyle( 'Text', stylesheet['Normal'], spaceBefore=1 * mm, spaceAfter=1 * mm, rightIndent=5 * mm, bulletIndent=2 * mm, leftIndent=5 * mm, ) class Questionnaire(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'report' obj_class = model.questionnaire.Questionnaire def init(self, small=0, suppress=None): self.small = small # iterate over qobjects for qobject in self.obj.qobjects: qobject.report.init(small, suppress) def report(self): # iterate over qobjects for qobject in self.obj.qobjects: qobject.report.report() def story(self): story = list() # iterate over qobjects keeptogether_list = [] for qobject in self.obj.qobjects: new, keeptogether = qobject.report.story() new = list(new) if len(new) == 0: continue if keeptogether: keeptogether_list.extend(new) else: if len(keeptogether_list): add = new.pop(0) if isinstance(add, platypus.KeepTogether): keeptogether_list.extend(add._content) else: keeptogether_list.append(add) story.append(platypus.KeepTogether(keeptogether_list)) keeptogether_list = [] story.extend(new) story.extend(keeptogether_list) return story def filters(self): filters = list() # iterate over qobjects for qobject in self.obj.qobjects: filters.extend(list(qobject.report.filters())) return filters class QObject(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'report' obj_class = model.questionnaire.QObject def init(self, small, suppress): self.small = small def report(self): pass def story(self): return [], False def filters(self): return [] class Head(QObject, metaclass=model.buddy.Register): name = 'report' obj_class = model.questionnaire.Head def story(self): return [ platypus.Paragraph( '%s %s' % (self.obj.id_str(), escape(self.obj.title)), stylesheet['Head'])], True class Question(QObject, metaclass=model.buddy.Register): name = 'report' obj_class = model.questionnaire.Question def story(self): return [ platypus.Paragraph( '%s %s' % ( self.obj.id_str(), escape(self.obj.question)), stylesheet['Question'])], True class Choice(Question, metaclass=model.buddy.Register): name = 'report' obj_class = model.questionnaire.Choice def init(self, small, suppress): self.small = small self.suppress = suppress self.text = list() def report(self): if not self.small: for box in self.obj.boxes: if (isinstance(box, model.questionnaire.Textbox) and box.data.state): if box.data.text and self.suppress != 'substitutions': self.text.append(answers.RawText(box.data.text, stylesheet['Text'])) elif self.suppress != 'images': self.text.append(answers.Freeform(box)) def story(self): story, tmp = Question.story(self) if self.obj.calculate.count: for box in self.obj.boxes: story.append( answers.Choice( box.text, self.obj.calculate.values[box.value], self.obj.calculate.significant[box.value] ) ) story = [platypus.KeepTogether(story)] if len(self.text) > 0: story.append(platypus.Spacer(0, 3 * mm)) story.extend(self.text) return story, False def filters(self): for box in self.obj.boxes: yield '%i in %s' % (box.value, self.obj.id_filter()) class Option(Question, metaclass=model.buddy.Register): name = 'report' obj_class = model.questionnaire.Option def filters(self): for box in self.obj.boxes: yield '%i == %s' % (box.value, self.obj.id_filter()) class Range(Option, metaclass=model.buddy.Register): name = 'report' obj_class = model.questionnaire.Range def report(self): pass def story(self): story, tmp = Question.story(self) if self.obj.calculate.range_count: story.append(answers.Range( self.obj.calculate.range_min, self.obj.calculate.range_max, self.obj.calculate.range_values, self.obj.answers, self.obj.calculate.mean, self.obj.calculate.standard_deviation, self.obj.calculate.count, self.obj.calculate.significant)) if self.obj.calculate.count > 0 and self.obj.calculate.values: for box in self.obj.boxes: if box.value in self.obj.calculate.values: story.append( answers.Choice( box.text, self.obj.calculate.values[box.value], False ) ) story = [platypus.KeepTogether(story)] return story, False class Text(Question, metaclass=model.buddy.Register): name = 'report' obj_class = model.questionnaire.Text def init(self, small, suppress): self.small = small self.suppress = suppress self.text = list() def report(self): if not self.small: for box in self.obj.boxes: if box.data.state: if box.data.text and self.suppress != 'substitutions': self.text.append(answers.RawText(box.data.text, stylesheet['Text'])) elif self.suppress != 'images': self.text.append(answers.Freeform(box)) def story(self): story, tmp = Question.story(self) if len(self.text) > 0: story.append(self.text[0]) story = [platypus.KeepTogether(story)] if len(self.text) > 1: story.extend(self.text[1:]) return story, False class Additional_FilterHistogram(Question, metaclass=model.buddy.Register): name = 'report' obj_class = model.questionnaire.Additional_FilterHistogram def story(self): story, tmp = Question.story(self) if self.obj.calculate.count: for i in range(len(self.obj.calculate.values)): story.append( answers.Choice( self.obj.answers[i], self.obj.calculate.values[i], self.obj.calculate.significant[i] ) ) story = [platypus.KeepTogether(story)] return story, False sdaps-1.9.8/sdaps/report/flowables.py0000644000175000000660000002151213367301321020354 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import math from reportlab import pdfgen from reportlab import platypus from reportlab.lib import styles from reportlab.lib import units from reportlab.lib import pagesizes from reportlab.lib import enums from sdaps import template mm = units.mm stylesheet = template.stylesheet stylesheet['Right'] = styles.ParagraphStyle( 'Right', parent=stylesheet['Normal'], alignment=enums.TA_RIGHT, ) class Box(platypus.Flowable): '''3d box ''' def __init__(self, a, b, c, margin=0): platypus.Flowable.__init__(self) self.a = float(a) self.b = float(b) self.c = float(c) self.margin = float(margin) self.alpha = 1.0 / 3.0 * math.pi self.cx = math.sin(self.alpha) * self.c self.cy = math.cos(self.alpha) * self.c self.fill = 0 self.transparent = 1 self.fill_color = (255, 255, 255) def wrap(self, available_width, available_height): self.width = self.a + self.cx self.height = self.b + self.cy + 2 * self.margin return self.width, self.height def draw(self): if 0: assert isinstance(self.canv, pdfgen.canvas.Canvas) self.canv.setLineJoin(1) self.canv.setLineWidth(0.2) self.canv.setFillColorRGB(*self.fill_color) # back if self.transparent: self.draw_front(self.cx, self.margin + self.cy) # left side if self.transparent: self.draw_side(0, self.margin) # bottom if self.transparent: self.draw_top(0, self.margin) # right side self.draw_side(self.a, self.margin) # top self.draw_top(0, self.margin + self.b) # front self.draw_front(0, self.margin) def draw_side(self, x, y): path = self.canv.beginPath() path.moveTo(x, y) path.lineTo(x + self.cx, y + self.cy) path.lineTo(x + self.cx, y + self.cy + self.b) path.lineTo(x, y + self.b) path.lineTo(x, y) self.canv.drawPath(path, fill=self.fill) def draw_top(self, x, y): path = self.canv.beginPath() path.moveTo(x, y) path.lineTo(x + self.a, y) path.lineTo(x + self.a + self.cx, y + self.cy) path.lineTo(x + self.cx, y + self.cy) path.lineTo(x, y) self.canv.drawPath(path, fill=self.fill) def draw_front(self, x, y): path = self.canv.beginPath() path.moveTo(x, y) path.lineTo(x + self.a, y) path.lineTo(x + self.a, y + self.b) path.lineTo(x, y + self.b) path.lineTo(x, y) self.canv.drawPath(path, fill=self.fill) #class ChoiceBar(platypus.Flowable): #def __init__(self, value): #platypus.Flowable.__init__(self) #self.a = 200 #self.b = 12 #self.depth_x = 6 #self.depth_y = 3 #self.value = value #def wrap(self, available_width, available_height): #self.width = self.a + self.depth_x #self.height = self.height + self.depth_y #return self.width, self.height #def draw(self): #if 0: assert isinstance(self.canv, pdfgen.canvas.Canvas) #self.canv.setLineJoin(1) #self.canv.setLineWidth(0.1) #self.canv.setFillGray(0.5) ## filling #self.draw_side(self.value, 1) #self.draw_top(self.value, 1) #self.draw_front(self.value, 1) ## line #self.canv.line(self.a * self.value, 0, self.a, 0) #self.canv.line(self.a * self.value + self.depth_x, self.depth_y, self.a + self.depth_x, self.depth_y) #self.canv.line(self.a * self.value, self.b, self.a, self.b) #self.canv.line(self.a * self.value + self.depth_x, self.b + self.depth_y, self.a + self.depth_x, self.b + self.depth_y) ## bar #self.draw_side(1, 0) #def draw_front(self, value, fill): #path = self.canv.beginPath() #path.moveTo(0, 0) #path.lineTo(self.a * value, 0) #path.lineTo(self.a * value, self.b) #path.lineTo(0, self.b) #path.lineTo(0, 0) #self.canv.drawPath(path, fill=fill) #def draw_top(self, value, fill): #path = self.canv.beginPath() #path.moveTo(0, self.b) #path.lineTo(self.a * value, self.b) #path.lineTo(self.a * value + self.depth_x, self.b + self.depth_y) #path.lineTo(self.depth_x, self.b + self.depth_y) #path.lineTo(0, self.b) #self.canv.drawPath(path, fill=fill) #def draw_side(self, value, fill): #path = self.canv.beginPath() #path.moveTo(self.a * value, 0) #path.lineTo(self.a * value, self.b) #path.lineTo(self.a * value + self.depth_x, self.b + self.depth_y) #path.lineTo(self.a * value + self.depth_x, self.depth_y) #path.lineTo(self.a * value, 0) #self.canv.drawPath(path, fill=fill) #class ChoiceAnswer(platypus.Flowable): #def __init__(self, answer, value): #platypus.Flowable.__init__(self) #self.answer = platypus.Paragraph(answer, template.stylesheet['Right']) #self.value = platypus.Paragraph(u'%.2f %%' %(value * 100), template.stylesheet['Right']) #self.bar = ChoiceBar(value) #self.gap = 3 #self.value_width = 42 #def wrap(self, available_width, available_height): #self.width = available_width #self.bar.wrap(self.width, available_height) #available_width -= self.bar.width #available_width -= self.gap #self.value.wrap(self.value_width, available_height) #available_width -= self.value.width #self.answer.wrap(available_width, available_height) #self.height = max(self.answer.height, self.bar.height, self.value.height) #return self.width, self.height #def draw(self): #if 0: assert isinstance(self.canv, pdfgen.canvas.Canvas) #self.answer.drawOn(self.canv, 0, 0) #self.value.drawOn(self.canv, self.answer.width, 0) #self.bar.drawOn(self.canv, self.answer.width + self.value.width + self.gap, 0) #class MarkAnswer(platypus.Flowable): #def __init__(self): #platypus.Flowable.__init__(self) #self.box_width = 40 #self.box_height = 60 #self.box_depth = 6 #self.mean_width = 2 #self.mean_height = 6 #self.margin = 6 ##self.values = [0.2, 0.20, 0.2, 0.20, 0.20] #self.values = [0.25, 0.10, 0.35, 0.20, 0.10] #self.mean = sum([(mark + 1) * value for mark, value in enumerate(self.values)]) #def wrap(self, available_width, available_height): #self.width = available_width #self.box_width * 5 #self.offset = self.width - self.box_width * 5 - self.margin #self.height = max(self.values) * self.box_height + self.mean_height #return self.width, self.height #def draw(self): #if 0: assert isinstance(self.canv, pdfgen.canvas.Canvas) #self.canv.setLineJoin(1) #self.canv.setLineWidth(0.1) #self.canv.setFillGray(0.5) ## mean #Box(self.mean_width, self.mean_height, self.box_depth).drawOn(self.canv, self.offset +(self.mean - 0.5) * self.box_width - self.mean_width / 2.0, 0) ## boxes #for i, value in enumerate(self.values): #Box(self.box_width, value * self.box_height, self.box_depth).drawOn(self.canv, self.offset + i * self.box_width, self.mean_height) ## skala #for i in range(41): #if i % 10 == 0: #self.canv.setLineWidth(0.2) #self.canv.line(self.offset +(i / 10.0 + 0.5) * self.box_width, 1, self.offset +(i / 10.0 + 0.5) * self.box_width, 5) #elif i % 5 == 0: #self.canv.line(self.offset +(i / 10.0 + 0.5) * self.box_width, 1.5, self.offset +(i / 10.0 + 0.5) * self.box_width, 4.5) #else: #self.canv.line(self.offset +(i / 10.0 + 0.5) * self.box_width, 2, self.offset +(i / 10.0 + 0.5) * self.box_width, 4) #if i % 10 == 0: #self.canv.setLineWidth(0.1) sdaps-1.9.8/sdaps/reporttex/0000755000175000000660000000000013611127124016543 5ustar benjaminlock00000000000000sdaps-1.9.8/sdaps/reporttex/__init__.py0000644000175000000660000001221413423054151020654 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, 2011, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """ This modules contains the functionality to create reports using LaTeX. """ import os import tempfile import shutil import glob from sdaps import model from sdaps import clifilter from sdaps import template from sdaps import matrix from sdaps import paths from sdaps import defs from sdaps.utils import latex from sdaps.utils import paper from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext from . import buddies import codecs def report(survey, filter, filename=None, papersize=None, small=0, suppress=None, tex_only=False): assert isinstance(survey, model.survey.Survey) # compile clifilter filter = clifilter.clifilter(survey, filter) # First: calculate buddies # init buddies survey.questionnaire.calculate.init() # iterate over sheets survey.iterate( survey.questionnaire.calculate.read, lambda: survey.sheet.valid and filter() ) # do calculations survey.questionnaire.calculate.calculate() # Temporary directory for TeX files. if tex_only and filename: tmpdir = filename # Create directory os.makedirs(tmpdir) else: tmpdir = tempfile.mkdtemp(prefix='sdaps-report-') # Second: report buddies # init buddies survey.questionnaire.report.init(tmpdir, small, suppress) # Filename of output if filename is None and tex_only == False: filename = survey.new_path('report_%i.pdf') try: # iterate over sheets survey.iterate( survey.questionnaire.report.report, lambda: survey.sheet.valid and filter(), tmpdir ) # Copy class and dictionary files if paths.local_run: cls_file = os.path.join(paths.source_dir, 'tex', 'sdapsreport.cls') dict_files = os.path.join(paths.build_dir, 'tex', '*.dict') dict_files = glob.glob(dict_files) else: cls_file = os.path.join(paths.prefix, 'share', 'sdaps', 'tex', 'sdapsreport.cls') dict_files = os.path.join(paths.prefix, 'share', 'sdaps', 'tex', '*.dict') dict_files = glob.glob(dict_files) shutil.copyfile(cls_file, os.path.join(tmpdir, 'sdapsreport.cls')) for dict_file in dict_files: shutil.copyfile(dict_file, os.path.join(tmpdir, os.path.basename(dict_file))) texfile = codecs.open(os.path.join(tmpdir, 'report.tex'), 'w', 'utf-8') author = _('author|Unknown') extra_info = [] for key, value in survey.info.items(): if key == 'Author': author = value continue extra_info.append('\\addextrainfo{%(key)s}{%(value)s}' % {'key': key, 'value': value}) extra_info = '\n'.join(extra_info) texfile.write(r"""\documentclass[%(language)s,%(papersize)s]{sdapsreport} \usepackage{ifxetex} \ifxetex \else \usepackage[utf8]{inputenc} \fi \usepackage[%(language)s]{babel} \title{%(title)s} \subject{%(title)s} \author{%(author)s} \addextrainfo{%(turned_in)s}{%(count)i} %(extra_info)s \begin{document} \maketitle """ % {'language': _('tex language|english'), 'title': _('sdaps report'), 'turned_in': _('Turned in Questionnaires'), 'title': survey.title, 'author': author, 'extra_info': extra_info, 'count': survey.questionnaire.calculate.count, 'papersize' : paper.get_tex_papersize(papersize)}) survey.questionnaire.report.write(texfile, tmpdir) texfile.write(r""" \end{document} """) texfile.close() if tex_only: print(_("The TeX project with the report data is located at '%s'.") % tmpdir) return print(_("Running %s now multiple times to generate the report.") % survey.defs.engine) latex.compile(survey.defs.engine, 'report.tex', cwd=tmpdir) if not os.path.exists(os.path.join(tmpdir, 'report.pdf')): print(_("Error running \"%s\" to compile the LaTeX file.") % survey.defs.engine) raise AssertionError('PDF file not generated') shutil.move(os.path.join(tmpdir, 'report.pdf'), filename) except: print(_("An occured during creation of the report. Temporary files left in '%s'." % tmpdir)) raise shutil.rmtree(tmpdir) sdaps-1.9.8/sdaps/reporttex/buddies.py0000644000175000000660000002112213367301321020533 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, 2011, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import cairo import math import os from sdaps import clifilter from sdaps import template from sdaps import model from sdaps import image from sdaps import calculate from sdaps.utils.latex import raw_unicode_to_latex, unicode_to_latex from sdaps.utils.image import ImageWriter def format_raw_text(text): from sdaps.setuptex import latexmap class Questionnaire(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'report' obj_class = model.questionnaire.Questionnaire def init(self, img_dir, small=0, suppress=None): self.small = small self.textbox_writer = ImageWriter(img_dir, 'textbox-') # iterate over qobjects for qobject in self.obj.qobjects: qobject.report.init(small, suppress) def report(self, tmpdir): # iterate over qobjects for qobject in self.obj.qobjects: qobject.report.report(tmpdir) def write(self, out, tmpdir): # iterate over qobjects for qobject in self.obj.qobjects: qobject.report.write(out, tmpdir) def filters(self): filters = list() # iterate over qobjects for qobject in self.obj.qobjects: filters.extend(list(qobject.report.filters())) return filters class QObject(model.buddy.Buddy, metaclass=model.buddy.Register): name = 'report' obj_class = model.questionnaire.QObject def init(self, small, suppress): self.small = small def report(self, tmpdir): pass def write(self, out, tmpdir): pass def filters(self): return [] class Head(QObject, metaclass=model.buddy.Register): name = 'report' obj_class = model.questionnaire.Head def write(self, out, tmpdir): # Smarter numbering handling? out.write('\\section*{%s %s}\n' % (self.obj.id_str(), unicode_to_latex(self.obj.title))) class Question(QObject, metaclass=model.buddy.Register): name = 'report' obj_class = model.questionnaire.Question def write_begin(self, out): # Smarter numbering handling? out.write('\\begin{question}{%s %s}\n' % (self.obj.id_str(), unicode_to_latex(self.obj.question))) def write_end(self, out): # Smarter numbering handling? out.write('\\end{question}\n\n') def write(self, out, tmpdir): self.write_begin(out) self.write_end(out) class Choice(Question, metaclass=model.buddy.Register): name = 'report' obj_class = model.questionnaire.Choice def init(self, small, suppress): self.small = small self.suppress = suppress self.text = "" def report(self, tmpdir): if not self.small: for box in self.obj.boxes: if (isinstance(box, model.questionnaire.Textbox) and box.data.state): if box.data.text and self.suppress != 'substitutions': text = raw_unicode_to_latex(box.data.text) self.text += '\\freeformtext{%s}\n' % (text) elif self.suppress != 'images': img_file = self.obj.questionnaire.report.textbox_writer.output_box(box) self.text += '\\freeform{%fmm}{%s}\n' % (box.data.width, img_file) def write_begin(self, out): # Smarter numbering handling? out.write('\\begin{choicequestion}{%s %s}\n' % (self.obj.id_str(), unicode_to_latex(self.obj.question))) def write_end(self, out): # Smarter numbering handling? out.write('\\end{choicequestion}\n\n') def write(self, out, tmpdir): self.write_begin(out) if self.obj.calculate.count: for box in self.obj.boxes: out.write('''\\choiceanswer{%s}{%.3f}\n''' % (unicode_to_latex(box.text), self.obj.calculate.values[box.value])) self.write_end(out) out.write(self.text) def filters(self): for box in self.obj.boxes: yield '%i in %s' % (box.value, self.obj.id_filter()) class Option(Choice, metaclass=model.buddy.Register): name = 'report' obj_class = model.questionnaire.Option def filters(self): for box in self.obj.boxes: yield '%i == %s' % (box.value, self.obj.id_filter()) class Range(Question, metaclass=model.buddy.Register): name = 'report' obj_class = model.questionnaire.Range def write(self, out, tmpdir): Question.write_begin(self, out) if self.obj.calculate.range_count: out.write('\\pgfkeyssetvalue{/sdaps/mark/range}{%s}\n' % (self.obj.calculate.range_max - self.obj.calculate.range_min + 1)) out.write('\\pgfkeyssetvalue{/sdaps/mark/rangemin}{%s}\n' % (self.obj.calculate.range_min)) out.write('\\pgfkeyssetvalue{/sdaps/mark/rangemax}{%s}\n' % (self.obj.calculate.range_max)) out.write('\\pgfkeyssetvalue{/sdaps/mark/lower}{%s}\n' % (unicode_to_latex(self.obj.answers[0]))) out.write('\\pgfkeyssetvalue{/sdaps/mark/upper}{%s}\n' % (unicode_to_latex(self.obj.answers[1]))) out.write('\\pgfkeyssetvalue{/sdaps/mark/count}{%i}\n' % (self.obj.calculate.count)) out.write('\\pgfkeyssetvalue{/sdaps/mark/stddev}{%.1f}\n' % (self.obj.calculate.standard_deviation)) for key in range(self.obj.calculate.range_min, self.obj.calculate.range_max + 1): if key in self.obj.calculate.range_values: fraction = self.obj.calculate.range_values[key] else: fraction = 0 out.write('\\pgfkeyssetvalue{/sdaps/mark/%i/fraction}{%.3f}\n' % (key, fraction)) out.write('\\pgfkeyssetvalue{/sdaps/mark/mean}{%.1f}\n' % (self.obj.calculate.mean)) out.write('\n\\markanswer\n') if self.obj.calculate.count > 0 and self.obj.calculate.values: out.write('\\begin{embedchoicequestion}\n') for box in self.obj.boxes: if box.value in self.obj.calculate.values: out.write('''\\choiceanswer{%s}{%.3f}\n''' % (unicode_to_latex(box.text), self.obj.calculate.values[box.value])) out.write('\\end{embedchoicequestion}\n') Question.write_end(self, out) def filters(self): for x in range(len(self.obj.boxes)+1): yield '%i == %s' % (x, self.obj.id_filter()) class Text(Question, metaclass=model.buddy.Register): name = 'report' obj_class = model.questionnaire.Text def init(self, small, suppress): self.small = small self.suppress = suppress self.text = "" def report(self, tmpdir): if not self.small: for box in self.obj.boxes: if box.data.state: if box.data.text and self.suppress != 'substitutions': text = raw_unicode_to_latex(box.data.text) self.text += '\\freeformtext{%s}\n' % (text) elif self.suppress != 'images': img_file = self.obj.questionnaire.report.textbox_writer.output_box(box) self.text += '\\freeform{%fmm}{%s}\n' % (box.data.width, img_file) def write(self, out, tmpdir): Question.write_begin(self, out) out.write(self.text) Question.write_end(self, out) class Additional_FilterHistogram(Question, metaclass=model.buddy.Register): name = 'report' obj_class = model.questionnaire.Additional_FilterHistogram def write(self, tmpdir): Question.write_begin(self, out) if self.obj.calculate.count: for i in range(len(self.obj.calculate.values)): out.write('''\\choiceanswer{%s}{%.3f}{%.3f}\n''' % (unicode_to_latex(self.obj.answers[i]), self.obj.calculate.values[i], self.obj.calculate.significant[i])) Question.write_end(self, out) sdaps-1.9.8/sdaps/reset/0000755000175000000660000000000013611127124015631 5ustar benjaminlock00000000000000sdaps-1.9.8/sdaps/reset/__init__.py0000644000175000000660000000234513473755263017767 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2012, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """ This module reset already stored data so next reports and exports will contain only new questionnaires. """ from collections import defaultdict from sdaps import model import bz2,os,pickle from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext def reset(survey): print((_("Removing stored data..."))) survey.iterate(lambda: survey.delete_sheet(survey.get_sheet())) survey.questionnaire_ids = [] survey.save() print((_("Done"))) sdaps-1.9.8/sdaps/script.py0000644000175000000660000000762013566240177016407 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . ''' This module defines some decorators, helping to implement sdaps-scripts. To register a function as a sdaps-script(callable from the command line), use @register ''' import sys import os import functools import argparse from . import __version__ from . import log from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext # Create parser if "sphinx" in sys.argv[0]: prog = "sdaps" else: prog = None description = _("SDAPS -- Paper based survey tool.") epilog = None parser = argparse.ArgumentParser(description=description, epilog=epilog, prog=prog) parser.add_argument('--version', help=_('Display version and exit'), action='version', version="%%(prog)s %s" % __version__) # Set required as an attribute rather than kwarg so that it works with python <3.7 subparsers = parser.add_subparsers(help=_("command list|Commands:"), dest='command') subparsers.required = True def add_subparser(*args, **kwargs): parser = subparsers.add_parser(*args, **kwargs) return parser def add_project_argument(parser): parser.add_argument('project', type=str, help=_("project directory|The SDAPS project.")) def add_project_subparser(*args, **kwargs): parser = add_subparser(*args, **kwargs) add_project_argument(parser) return parser def doc(docstring): '''decorator to add a docstring to a function. When using normal Python docstring syntax it cannot be generated dynamically. Using this one can for example add translations. >>> @doc(_(u'docstring')) >>> def function(*args, **kwargs): >>> pass ''' def decorator(function): function.__doc__ = docstring return function return decorator def connect(parser, name=None): '''decorator to connect an already prepared parser to call into a function. This function initilizes the _func and _name properties for the parser to the given function, and its name. It also sets the functions docstring to be the parsers help. This way the help string appears in the sphinx documentation for the function. >>> @script.connect(parser) >>> def add(cmdline): >>> pass ''' def decorator(function): # Use the function name as a fallback, it should be the same usually. if name is None: local_name = function.__name__ else: local_name = name parser.set_defaults(_func=function, _name=local_name) function.__doc__ = parser.format_help() return function return decorator def logfile(function): '''open the logfile when running the function and close it afterwards. >>> @logfile >>> def function(survey_dir, *args, **kwargs): >>> pass @logfile will open survey_dir/log as a logfile when function is called and close it, when function finishes. ''' def decorated_function(cmdline): log.logfile.open(os.path.join(cmdline['project'], 'log')) result = function(cmdline) log.logfile.close() return result functools.update_wrapper(decorated_function, function) return decorated_function sdaps-1.9.8/sdaps/setup/0000755000175000000660000000000013611127124015647 5ustar benjaminlock00000000000000sdaps-1.9.8/sdaps/setup/__init__.py0000644000175000000660000000000013346275473017766 0ustar benjaminlock00000000000000sdaps-1.9.8/sdaps/setup/additionalparser.py0000644000175000000660000000245013346275473021567 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from sdaps import model def parse(survey, additionalqobjects): document = file(additionalqobjects, 'r') for line in document: line = line.decode('utf-8') args = line.strip().split('\t') qobject = getattr(model.questionnaire, 'Additional_%s' % args.pop(0)) assert issubclass(qobject, model.questionnaire.QObject) qobject = qobject() survey.questionnaire.add_qobject(qobject) qobject.setup.setup(args) sdaps-1.9.8/sdaps/setup/buddies.py0000644000175000000660000002120513367301321017641 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from sdaps import model from sdaps import log from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext class QObject(model.buddy.Buddy, metaclass=model.buddy.Register): obj_class = model.questionnaire.QObject name = 'setup' def init(self): pass def question(self, chars): raise AssertionError('Setting a question on this QObject type is not possible.') def answer(self, chars): raise AssertionError('Adding an answer to this QObject type is not possible.') def box(self, box): raise AssertionError('Adding a box to this QObject type is not possible.') def variable_name(self, value): self.obj.var = value def validate(self): pass def setup(self, *args): pass class Head(QObject, metaclass=model.buddy.Register): obj_class = model.questionnaire.Head def question(self, chars): self.obj.title += chars.strip() def validate(self): if not self.obj.title: log.warn(_('Head %(l0)i got no title.') % {'l0': self.obj.id[0]}) class Question(QObject, metaclass=model.buddy.Register): obj_class = model.questionnaire.Question def question(self, chars): self.obj.question += chars.strip() def validate(self): if not self.obj.question: log.warn(_('%(class)s %(l0)i.%(l1)i got no question.') % { 'class': self.obj.__class__.__name__, 'l0': self.obj.id[0], 'l1': self.obj.id[1] }) class Choice(Question, metaclass=model.buddy.Register): obj_class = model.questionnaire.Choice def init(self): self.box_cache = list() self.answer_cache = list() def _box(self, box): self.obj.add_box(box) if self.obj.page_number == 0: self.obj.page_number = box.page_number else: assert self.obj.page_number == box.page_number def answer(self, chars): self.answer_cache.append(chars) def box(self, box): self.box_cache.append(box) def setup(self): while self.box_cache and self.answer_cache: box = self.box_cache.pop(0) answer = self.answer_cache.pop(0) box.setup.answer(answer) self._box(box) Question.setup(self) def validate(self): Question.validate(self) if self.box_cache or self.answer_cache: raise AssertionError(_("Error in question \"%s\"") % self.obj.question) del self.box_cache del self.answer_cache if not self.obj.boxes: log.warn(_('%(class)s %(l0)i.%(l1)i got no boxes.') % { 'class': self.obj.__class__.__name__, 'l0': self.obj.id[0], 'l1': self.obj.id[1] }) class Option(Choice, metaclass=model.buddy.Register): obj_class = model.questionnaire.Option class Range(Option, metaclass=model.buddy.Register): obj_class = model.questionnaire.Range def set_lower(self, box, answer): self.obj.answers = (answer, self.obj.answers[1]) self.obj.range = (box, self.obj.range[1]) def set_upper(self, box, answer): self.obj.answers = (self.obj.answers[0], answer) self.obj.range = (self.obj.range[0], box) def setup(self): # TODO: This happens while parsing the ODT, verify why and figure out # whether this is the reasonable solution to it. if not self.box_cache: Option.setup(self) return # Insert None answer texts for the boxes part of the range range_len = self.obj.range[1] - self.obj.range[0] + 1 self.answer_cache = \ self.answer_cache[:self.obj.range[0]] + \ [None for i in range(range_len)] + \ self.answer_cache[self.obj.range[0]:] # Run normal setup routine which will match up the answers outside # the range correctly now. Option.setup(self) def validate(self): Option.validate(self) boxes = len(self.obj.boxes) if not (0 <= self.obj.range[0] < boxes): log.warn(_('%(class)s %(l0)i.%(l1)i lower box out of range.') % { 'class': self.obj.__class__.__name__, 'l0': self.obj.id[0], 'l1': self.obj.id[1] }) if not (0 <= self.obj.range[1] < boxes): log.warn(_('%(class)s %(l0)i.%(l1)i upper box out of range.') % { 'class': self.obj.__class__.__name__, 'l0': self.obj.id[0], 'l1': self.obj.id[1] }) if not (self.obj.range[0] < self.obj.range[1]): log.warn(_('%(class)s %(l0)i.%(l1)i lower box not before upper box.') % { 'class': self.obj.__class__.__name__, 'l0': self.obj.id[0], 'l1': self.obj.id[1] }) class Mark(Range, metaclass=model.buddy.Register): obj_class = model.questionnaire.Mark def init(self): Range.init(self) self.answer_count = 0 def answer(self, chars): if self.answer_count == 0: self.obj.answers = (chars, '') elif self.answer_count == 1: self.obj.answers = (self.obj.answers[0], chars) self.answer_count += 1 def box(self, box): assert isinstance(box, model.questionnaire.Checkbox) self.obj.add_box(box) box.value = len(self.obj.boxes) if self.obj.page_number == 0: self.obj.page_number = box.page_number else: assert self.obj.page_number == box.page_number self.obj.range = (0, len(self.obj.boxes) - 1) def validate(self): Range.validate(self) if self.answer_count != 2: log.warn(_('%(class)s %(l0)i.%(l1)i got not exactly two answers.') % { 'class': self.obj.__class__.__name__, 'l0': self.obj.id[0], 'l1': self.obj.id[1] }) class Text(Question, metaclass=model.buddy.Register): obj_class = model.questionnaire.Text def box(self, box): assert isinstance(box, model.questionnaire.Textbox) self.obj.add_box(box) if self.obj.page_number == 0: self.obj.page_number = box.page_number else: assert self.obj.page_number == box.page_number def validate(self): Question.validate(self) if not len(self.obj.boxes) == 1: log.warn(_('%(class)s %(l0)i.%(l1)i got not exactly one box.') % { 'class': self.obj.__class__.__name__, 'l0': self.obj.id[0], 'l1': self.obj.id[1] }) class Additional_Head(Head, metaclass=model.buddy.Register): obj_class = model.questionnaire.Additional_Head def setup(self, args): assert len(args) == 1 self.question(args[0]) self.validate() class Additional_Mark(Question, metaclass=model.buddy.Register): obj_class = model.questionnaire.Additional_Mark def setup(self, args): assert len(args) == 3 self.question(args[0]) self.obj.answers.append(args[1]) self.obj.answers.append(args[2]) self.validate() class Additional_FilterHistogram(Question, metaclass=model.buddy.Register): obj_class = model.questionnaire.Additional_FilterHistogram def setup(self, args): assert len(args) % 2 == 1 self.question(args.pop(0)) while len(args): self.obj.answers.append(args.pop(0)) self.obj.filters.append(args.pop(0)) self.validate() class Box(model.buddy.Buddy, metaclass=model.buddy.Register): obj_class = model.questionnaire.Box name = 'setup' def setup(self, page_number, x, y, width, height, lw=None): self.obj.page_number = page_number self.obj.x = x self.obj.y = y self.obj.width = width self.obj.height = height if lw is not None: self.obj.lw = lw def answer(self, text): self.obj.text = text sdaps-1.9.8/sdaps/setuptex/0000755000175000000660000000000013611127124016370 5ustar benjaminlock00000000000000sdaps-1.9.8/sdaps/setuptex/__init__.py0000644000175000000660000001466113432542242020514 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2010, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """ Contains the functionality to create a new SDAPS project using a LaTeX input file. """ import sys import os import shutil import glob from sdaps.utils.mimetype import mimetype from sdaps import model from sdaps import log from sdaps import paths from sdaps import defs from sdaps.utils import latex from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext from ..setup import buddies from . import sdapsfileparser from ..setup import additionalparser def setup(survey_dir, questionnaire_tex, engine, additionalqobjects=None, extra_files=[]): if os.access(survey_dir, os.F_OK): log.error(_('The survey directory already exists.')) return 1 mime = mimetype(questionnaire_tex) if mime != 'text/x-tex' and mime != '': log.warn(_('Unknown file type (%s). questionnaire_tex should be of type text/x-tex.') % mime) log.warn(_('Will keep going, but expect failure!')) if additionalqobjects is not None: mime = mimetype(additionalqobjects) if mime != 'text/plain' and mime != '': log.error(_('Unknown file type (%s). additionalqobjects should be text/plain.') % mime) return 1 # Create the survey directory, and copy the tex file. survey = model.survey.Survey.new(survey_dir) survey.defs.engine = engine # Add the new questionnaire survey.add_questionnaire(model.questionnaire.Questionnaire()) try: shutil.copy(questionnaire_tex, survey.path('questionnaire.tex')) latex.write_override(survey, survey.path('sdaps.opt'), draft=True) # Copy class and dictionary files if paths.local_run: cls_extra_files = os.path.join(paths.source_dir, 'tex', '*.cls') cls_files = os.path.join(paths.source_dir, 'tex', 'class', 'build', 'local', '*.cls') tex_files = os.path.join(paths.source_dir, 'tex', 'class', 'build', 'local', '*.tex') sty_files = os.path.join(paths.source_dir, 'tex', 'class', 'build', 'local', '*.sty') dict_files = os.path.join(paths.build_dir, 'tex', '*.dict') else: cls_extra_files = None cls_files = os.path.join(paths.prefix, 'share', 'sdaps', 'tex', '*.cls') tex_files = os.path.join(paths.prefix, 'share', 'sdaps', 'tex', '*.tex') sty_files = os.path.join(paths.prefix, 'share', 'sdaps', 'tex', '*.sty') dict_files = os.path.join(paths.prefix, 'share', 'sdaps', 'tex', '*.dict') def copy_to_survey(files_glob): files = glob.glob(files_glob) for file in files: shutil.copyfile(file, survey.path(os.path.basename(file))) if cls_extra_files is not None: copy_to_survey(cls_extra_files) copy_to_survey(cls_files) copy_to_survey(tex_files) copy_to_survey(sty_files) copy_to_survey(dict_files) for add_file in extra_files: if os.path.isdir(add_file): shutil.copytree(add_file, survey.path(os.path.basename(add_file))) else: shutil.copyfile(add_file, survey.path(os.path.basename(add_file))) print(_("Running %s now multiple times to generate the questionnaire.") % survey.defs.engine) latex.compile(survey.defs.engine, 'questionnaire.tex', cwd=survey.path()) if not os.path.exists(survey.path('questionnaire.pdf')): print(_("Error running \"%s\" to compile the LaTeX file.") % defs.latex_engine) raise AssertionError('PDF file not generated') survey.defs.print_questionnaire_id = False survey.defs.print_survey_id = True # Parse qobjects try: sdapsfileparser.parse(survey) for qobject in survey.questionnaire.qobjects: qobject.setup.setup() qobject.setup.validate() except: log.error(_("Caught an Exception while parsing the SDAPS file. The current state is:")) print(str(survey.questionnaire), file=sys.stderr) print("------------------------------------", file=sys.stderr) raise # Parse additionalqobjects if additionalqobjects: additionalparser.parse(survey, additionalqobjects) # Last but not least calculate the survey id survey.calculate_survey_id() if not survey.check_settings(): log.error(_("Some combination of options and project properties do not work. Aborted Setup.")) shutil.rmtree(survey.path()) return 1 # We need to now rebuild everything so that the correct ID is at the bottom # Dissable draft mode if the survey doesn't have questionnaire IDs latex.write_override(survey, survey.path('sdaps.opt'), draft=survey.defs.print_questionnaire_id) print(_("Running %s now multiple imes to generate the questionnaire.") % survey.defs.engine) os.remove(survey.path('questionnaire.pdf')) latex.compile(survey.defs.engine, 'questionnaire.tex', survey.path()) if not os.path.exists(survey.path('questionnaire.pdf')): print(_("Error running \"%s\" to compile the LaTeX file.") % survey.defs.engine) raise AssertionError('PDF file not generated') # Print the result print(survey.title) for item in list(survey.info.items()): print('%s: %s' % item) log.logfile.open(survey.path('log')) survey.save() log.logfile.close() except: log.error(_("An error occured in the setup routine. The survey directory still exists. You can for example check the questionnaire.log file for LaTeX compile errors.")) raise sdaps-1.9.8/sdaps/setuptex/sdapsfileparser.py0000644000175000000660000001707413566240177022157 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from sdaps import log import xml.sax import zipfile import re from sdaps import model from sdaps.utils.latex import latex_to_unicode QOBJECT_PREFIX = 'QObject' ANSWER_PREFIX = 'Answer' BOX = 'Box' VARIABLE = 'Variable' TEXTBOX = 'Textbox' RANGE_PREFIX = 'Range' index_re = re.compile(r'''^(?P(?:[0-9]+\.)+)(?P.*)$''') arg_index_re = re.compile(r'''^(?P[^\[]*)(\[(?P([0-9]+\.)*[0-9]+)\])?$''') def get_index_and_string(string): match = index_re.match(string) if match is None: if string.startswith('XAUTO. '): return None, string[7:] return None, string string = match.group('string') index = match.group('index') index = index.split('.')[:-1] index = tuple([int(x) for x in index]) return index, string def parse(survey): sdaps_file = open(survey.path('questionnaire.sdaps')) # the file is encoded in ascii format sdaps_data = sdaps_file.read() qobject = None auto_numbering_id = (0,) sdaps_data = sdaps_data.split('\n') if sdaps_data[0].startswith('['): lines = [] for line in sdaps_data: # Ignore empty lines if not line: continue num, line = line.split(']', 1) num = int(num[1:]) lines.append((num, line)) lines.sort(key=lambda x: x[0]) sdaps_data = [l[1] for l in lines] for line in sdaps_data: line = line.strip() if line == "": continue arg, value = line.split('=', 1) arg = arg.strip() value = value.strip() value = latex_to_unicode(value) match = arg_index_re.match(arg) if match is not None: arg = match.group('arg') index = match.group('index') if index is None: try: survey.questionnaire.qobjects[-1] except IndexError: pass else: index = tuple([int(s) for s in index.split('.')]) qobject = survey.questionnaire.find_object(index) if arg == 'Title': survey.title = value elif arg == 'PrintQuestionnaireId': survey.defs.print_questionnaire_id = bool(int(value)) elif arg == 'PrintSurveyId': survey.defs.print_survey_id = bool(int(value)) elif arg == 'Pages': survey.questionnaire.page_count = int(value) elif arg == 'CheckMode': survey.defs.checkmode = value assert survey.defs.checkmode in model.survey.valid_checkmodes elif arg == 'GlobalID': survey.global_id = value elif arg == 'GlobalIDLabel': # Ignore for now pass elif arg == 'Duplex': survey.defs.duplex = (value.lower() == "true") elif arg == 'Style': survey.defs.style = value assert survey.defs.style in model.survey.valid_styles elif arg == "PageSize": args = value.split(',') args = [arg.strip() for arg in args] width, height = [round(float(arg[:-2]) / 72.27 * 25.4, 3) for arg in args] survey.defs.paper_width = width survey.defs.paper_height = height elif arg.startswith(QOBJECT_PREFIX): index, string = get_index_and_string(value) if index: auto_numbering_id = index + (0,) else: auto_numbering_id = auto_numbering_id[:-1] + (auto_numbering_id[-1] + 1,) index = auto_numbering_id qobject_type = arg[len(QOBJECT_PREFIX) + 1:] qobject_type = qobject_type.lower().capitalize() qobject = getattr(model.questionnaire, qobject_type) assert issubclass(qobject, model.questionnaire.QObject) qobject = qobject() survey.questionnaire.add_qobject(qobject, new_id=index) qobject.setup.init() qobject.setup.question(string) elif arg == VARIABLE: assert qobject is not None qobject.setup.variable_name(value) elif arg.startswith(ANSWER_PREFIX): assert qobject is not None answer_type = arg[len(ANSWER_PREFIX) + 1:] qobject.setup.answer(value) elif arg.startswith(RANGE_PREFIX): assert qobject is not None assert isinstance(qobject, model.questionnaire.Range) idx, answer = value.split(',', 1) idx = int(idx) range_type = arg[len(RANGE_PREFIX) + 1:].lower() if range_type == 'lower': qobject.setup.set_lower(idx, answer) elif range_type == 'upper': qobject.setup.set_upper(idx, answer) else: raise AssertionError('File format error, %s has to be either lower or upper!' % RANGE_PREFIX) elif arg == BOX: args = value.split(',') args = [arg.strip() for arg in args] boxtype = args[0] # Convert to mm page = int(args[1]) x, y, width, height = [float(arg[:-2]) / 72.27 * 25.4 for arg in args[2:6]] y = survey.defs.paper_height - y lw = None if boxtype == 'Textbox': box = model.questionnaire.Textbox() if len(args) == 9: lw = args[6] if args[6] else None box.var = args[7] if args[7] else None box.value = int(args[8]) if args[8] else None else: assert(len(args) == 6) elif boxtype == 'Codebox': box = model.questionnaire.Codebox() if len(args) == 9: lw = args[6] if args[6] else None box.var = args[7] if args[7] else None box.value = int(args[8]) if args[8] else None else: assert(len(args) == 6) else: box = model.questionnaire.Checkbox() if len(args) == 7: box.form = args[6] elif len(args) == 10: box.form = args[6] lw = args[7] if args[7] else None box.var = args[8] if args[8] else None box.value = int(args[9]) if args[9] else None else: assert(len(args) == 6) if lw: lw = float(lw[:-2]) / 72.27 * 25.4 box.setup.setup(page, x, y, width, height, lw) qobject.setup.box(box) else: # Falltrough, it is some metadata: survey.info[arg] = value # Force duplex of for one page questionnaires if survey.questionnaire.page_count == 1: survey.defs.duplex = False sdaps-1.9.8/sdaps/stamp/0000755000175000000660000000000013611127124015633 5ustar benjaminlock00000000000000sdaps-1.9.8/sdaps/stamp/__init__.py0000644000175000000660000000656213367301321017756 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import random import os import sys import math import codecs from sdaps import model from sdaps import log from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext def stamp(survey, output_filename, cmdline): # copy questionnaire_ids # get number of sheets to create if cmdline['file'] or cmdline['random'] or cmdline['existing']: if not survey.defs.print_questionnaire_id: log.error(_("You may not specify the number of sheets for this survey. All questionnaires will be identical as the survey has been configured to not use questionnaire IDs for each sheet.")) return 1 if cmdline['existing']: questionnaire_ids = survey.questionnaire_ids elif cmdline['file']: if cmdline['file'] == '-': fd = sys.stdin else: fd = codecs.open(cmdline['file'], 'r', encoding="utf-8") questionnaire_ids = list() for line in fd.readlines(): # Only strip newline/linefeed not spaces line = line.strip('\n\r') # Skip empty lines if line == "": continue questionnaire_ids.append(survey.validate_questionnaire_id(line)) else: # Create random IDs max = pow(2, 16) min = max - 50000 questionnaire_ids = list(range(min, max)) # Remove any id that has already been used. for id in survey.questionnaire_ids: if type(id) != int: continue questionnaire_ids[id - min] = 0 questionnaire_ids = [id for id in questionnaire_ids if id > min] random.shuffle(questionnaire_ids) questionnaire_ids = questionnaire_ids[:cmdline['random']] else: if survey.defs.print_questionnaire_id: log.error(_("This survey has been configured to use questionnaire IDs. Each questionnaire will be unique. You need to use on of the options to add new IDs or use the existing ones.")) return 1 questionnaire_ids = None if questionnaire_ids is not None and not cmdline['existing']: survey.questionnaire_ids.extend(questionnaire_ids) if os.path.exists(survey.path('questionnaire.tex')): # use the LaTeX stamper from sdaps.stamp.latex import create_stamp_pdf else: raise AssertionError('Only LaTeX stamping is currently supported!') create_stamp_pdf(survey, output_filename, questionnaire_ids) survey.save() sdaps-1.9.8/sdaps/stamp/latex.py0000644000175000000660000000261613423054175017335 0ustar benjaminlock00000000000000 import sys import os import tempfile import shutil from sdaps import log from sdaps import paths from sdaps import defs from sdaps.utils import latex from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext def create_stamp_pdf(survey, output_filename, questionnaire_ids): if questionnaire_ids is None: log.warn(_("There should be no need to stamp a SDAPS Project that uses LaTeX and does not have different questionnaire IDs printed on each sheet.\nI am going to do so anyways.")) # Temporary directory for TeX files. tmpdir = tempfile.mkdtemp(prefix='sdaps-stamp-') try: latex.write_override(survey, os.path.join(tmpdir, 'sdaps.opt'), questionnaire_ids=questionnaire_ids) print(_("Running %s now multiple times to generate the stamped questionnaire.") % survey.defs.engine) latex.compile(survey.defs.engine, 'questionnaire.tex', tmpdir, inputs=[os.path.abspath(survey.path())]) if not os.path.exists(os.path.join(tmpdir, 'questionnaire.pdf')): log.error(_("Error running \"%s\" to compile the LaTeX file.") % defs.latex_engine) raise AssertionError('PDF file not generated') shutil.move(os.path.join(tmpdir, 'questionnaire.pdf'), output_filename) except: log.error(_("An error occured during creation of the report. Temporary files left in '%s'." % tmpdir)) raise shutil.rmtree(tmpdir) sdaps-1.9.8/sdaps/surface.py0000644000175000000660000000703013367301321016512 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """ The surface module adds support for loading the scanned images. It adds a buddy to the model.sheet.Image and provides the surface via model.sheet.Image.surface.surface at runtime. """ from . import model from . import image class Image(model.buddy.Buddy, metaclass=model.buddy.Register): """ Buddy to load and cache image data. Do not forget to call :py:meth:`clean` when you are done (ie. before moving to the next sheet) or else the surface will be cached indefinately. :ivar surface: The cairo A1 surface, after it has been loaded using :py:meth:`load`. :ivar surface_rgb: The cairo RGB24 surface, after it has been loaded using :py:meth:`load_rgb`. """ name = 'surface' obj_class = model.sheet.Image def load(self): """Load the A1 cairo surface, which is accessible using the surface attribute. :py:meth`clean` needs to be called when the surface is no longer needed.""" self.surface = image.get_a1_from_tiff( self.obj.sheet.survey.path(self.obj.filename), self.obj.tiff_page, True if self.obj.rotated else False ) def load_rgb(self): """Load the RGB24 cairo surface, which is accessible using the surface_rgb attribute. :py:meth:`clean` needs to be called when the surface is no longer needed.""" self.surface_rgb = image.get_rgb24_from_tiff( self.obj.sheet.survey.path(self.obj.filename), self.obj.tiff_page, True if self.obj.rotated else False ) def load_uncached(self): """Load the A1 surface and directly return it. It will not be cached, so using this function may result repeated reloads from file.""" if hasattr(self, 'surface'): return self.surface else: return image.get_a1_from_tiff( self.obj.sheet.survey.path(self.obj.filename), self.obj.tiff_page, True if self.obj.rotated else False) def get_size(self): """Read the size of the surface. If the surface is already loaded, it will read the size from that. If it is not loaded, an uncached load will be done, which may be rather slow.""" # Load uncached does not check the rgb surface if hasattr(self, 'surface_rgb'): s = self.surface_rgb else: s = self.load_uncached() return s.get_width(), s.get_height() def clean(self): """Call when you are done handling a specific sheet to free any cached cairo surface.""" if hasattr(self, 'surface'): del self.surface if hasattr(self, 'surface_rgb'): del self.surface_rgb sdaps-1.9.8/sdaps/template.py0000644000175000000660000001126513367301321016702 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """ Template ======== This modules contains templates for reportlab. These are used to create the reports. """ from reportlab import platypus from reportlab.lib import styles from reportlab.lib import units from reportlab.lib import pagesizes mm = units.mm PADDING = 15 * mm class DocTemplate(platypus.BaseDocTemplate): def __init__(self, filename, title, metainfo={}, papersize=pagesizes.A4): platypus.BaseDocTemplate.__init__( self, filename, pagesize=papersize, leftMargin=0, rightMargin=0, topMargin=0, bottomMargin=0, **metainfo ) #pageTemplates=[], #showBoundary=0, #allowSplitting=1, #title=None, #author=None, #_pageBreakQuick=1 self.addPageTemplates(TitlePageTemplate(papersize, title)) self.addPageTemplates(PageTemplate(papersize)) class TitlePageTemplate(platypus.PageTemplate): def __init__(self, papersize, title): self.title = title frames = [ platypus.Frame( PADDING, papersize[1] / 2, papersize[0] - 2*PADDING, papersize[1] / 6, showBoundary=0 ), platypus.Frame( PADDING, PADDING, papersize[0] - 2*PADDING, papersize[1] / 2 - PADDING, showBoundary=0 ), ] platypus.PageTemplate.__init__( self, id='Title', frames=frames, ) def beforeDrawPage(self, canvas, document): canvas.saveState() canvas.setFont('Times-Bold', 24) canvas.drawCentredString( document.width / 2.0, document.height - 50 * mm, self.title ) canvas.restoreState() def afterDrawPage(self, canvas, document): pass class PageTemplate(platypus.PageTemplate): def __init__(self, papersize): frames = [ platypus.Frame( PADDING, PADDING, papersize[0] - 2*PADDING, papersize[1] - 2*PADDING, showBoundary=0 ) ] platypus.PageTemplate.__init__( self, id='Normal', frames=frames, ) self.frames def beforeDrawPage(self, canvas, document): pass def afterDrawPage(self, canvas, document): pass stylesheet = dict() stylesheet['Normal'] = styles.ParagraphStyle( 'Normal', fontName='Times-Roman', fontSize=10, leading=14, ) stylesheet['Title'] = styles.ParagraphStyle( 'Title', parent=stylesheet['Normal'], fontSize=18, leading=22, alignment=styles.TA_CENTER, ) def story_title(survey, info=dict()): story = [ platypus.Paragraph(str(line), stylesheet['Title']) for line in survey.title.split('\n') ] story += [ platypus.FrameBreak(), ] keys = list(survey.info.keys()) if keys: keys.sort() table = [ [ platypus.Paragraph(str(key), stylesheet['Normal']), platypus.Paragraph(str(survey.info[key]), stylesheet['Normal']) ] for key in keys ] story += [ platypus.Table(table, colWidths=(50 * mm, None)), ] if info: story += [ platypus.Spacer(0, 10 * mm) ] keys = list(info.keys()) keys.sort() table = [ [ platypus.Paragraph(str(key), stylesheet['Normal']), platypus.Paragraph(str(info[key]), stylesheet['Normal']) ] for key in keys ] story += [ platypus.Table(table, colWidths=(50 * mm, None)), ] story += [ platypus.NextPageTemplate('Normal'), platypus.PageBreak() ] return story sdaps-1.9.8/sdaps/utils/0000755000175000000660000000000013611127124015647 5ustar benjaminlock00000000000000sdaps-1.9.8/sdaps/utils/__init__.py0000644000175000000660000000000013346275473017766 0ustar benjaminlock00000000000000sdaps-1.9.8/sdaps/utils/barcode.py0000644000175000000660000000675213452121156017634 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2012, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """ This module contains helpers to read barcodes from cairo A1 surfaces. """ from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext import os import tempfile import cairo import subprocess from sdaps import image from sdaps import defs def read_barcode(surface, matrix, x, y, width, height, btype="CODE128"): """Tries to read the barcode at the given position""" result = scan(surface, matrix, x, y, width, height, btype) if result == None: # Try kfill approach result = scan(surface, matrix, x, y, width, height, btype, True) return result def scan(surface, matrix, x, y, width, height, btype="CODE128", kfill=False): x0, y0 = matrix.transform_point(x, y) x1, y1 = matrix.transform_point(x + width, y + height) # Bounding box ... x = min(x0, x1) y = min(y0, y1) width = max(x0, x1) - x height = max(y0, y1) - y x, y, width, height = int(x), int(y), int(width), int(height) # Round the width to multiple of 4 pixel, so that the stride will # be good ... hopefully width = width - width % 4 + 4 # a1 surface for kfill algorithm a1_surface = cairo.ImageSurface(cairo.FORMAT_A1, width, height) cr = cairo.Context(a1_surface) cr.set_operator(cairo.OPERATOR_SOURCE) cr.set_source_surface(surface, -x, -y) cr.paint() if kfill: pxpermm = (matrix[0] + matrix[3]) / 2 barwidth = pxpermm * defs.code128_barwidth barwidth = int(round(barwidth)) if barwidth <= 3: return if barwidth > 6: barwidth = 6 image.kfill_modified(a1_surface, barwidth) pbm = image.get_pbm(a1_surface) tmp = tempfile.mktemp(suffix='.png', prefix='sdaps-zbar-') f = open(tmp, 'wb') f.write(pbm) f.close() # Is the /dev/stdin sufficiently portable? proc = subprocess.Popen(['zbarimg', '-q', '-Sdisable', '-S%s.enable' % btype.lower(), tmp], stdout=subprocess.PIPE) stdout, stderr = proc.communicate() os.unlink(tmp) # The following can be used to look at the images #rgb_surface = cairo.ImageSurface(cairo.FORMAT_RGB24, width, height) #cr = cairo.Context(rgb_surface) #cr.set_operator(cairo.OPERATOR_SOURCE) #cr.set_source_rgba(1, 1, 1, 1) #cr.paint() #cr.set_operator(cairo.OPERATOR_OVER) #cr.set_source_rgba(0, 0, 0, 1) #cr.mask_surface(a1_surface) #global b_count #rgb_surface.write_to_png("/tmp/barcode-%03i.png" % b_count) #b_count += 1 if proc.returncode == 4: return None assert(proc.returncode == 0) barcode = stdout.split(b'\n')[0] assert barcode.split(b':', 1)[0].replace(b'-', b'').lower() == btype.lower().encode('ascii') return barcode.split(b':', 1)[1].decode('utf-8') #b_count = 0 sdaps-1.9.8/sdaps/utils/create-latexmap.py0000755000175000000660000000333513367301321021305 0ustar benjaminlock00000000000000#!/usr/bin/env python3 # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2011, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """ This file generates the latexmap.py file which is needed to convert latex symbols into their unicode counterpart. Run with create-latexmap.py path/to/utf8enc.dfu """ import re import sys if len(sys.argv) != 2: print(__doc__) sys.exit(1) output = open('latexmap.py', 'w') input = open(sys.argv[1]) data = input.read() regexp = re.compile(r'^\\DeclareUnicodeCharacter\{(?P[0-9a-fA-F]{4})\}\{(?P[^\}]+)\}', re.MULTILINE) mapping = [] for match in regexp.finditer(data): repr = match.group('str') repr = repr.replace('\\@tabacckludge', '\\') repr = repr.replace('\\', '\\\\').replace('\'', '\\\'') mapping.append(''' u\'%s\': u\'\\u%s\'''' % (repr, match.group('unicode'))) output.write('''#This file is auto generated from the latex unicode mapping. #: Mapping from LaTeX commands to unicode characters. mapping = { ''') output.write(',\n'.join(mapping)) output.write(''' } ''') sdaps-1.9.8/sdaps/utils/exceptions.py0000644000175000000660000000160013346275473020417 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or #(at your option) any later version # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . class RecognitionError(Exception): pass sdaps-1.9.8/sdaps/utils/image.py0000644000175000000660000000723013346275473017325 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, 2011, 2014, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # Ensure the matrix buddy is loaded from sdaps import matrix from sdaps import image import cairo import math import os import os.path def get_box_surface(img, filename, x, y, width, height, format=cairo.FORMAT_RGB24): mm_to_px = img.matrix.mm_to_px() x0, y0 = mm_to_px.transform_point(x, y) x1, y1 = mm_to_px.transform_point(x + width, y) x2, y2 = mm_to_px.transform_point(x, y + height) x3, y3 = mm_to_px.transform_point(x + width, y + height) x = int(min(x0, x1, x2, x3)) y = int(min(y0, y1, y2, y3)) width = int(math.ceil(max(x0, x1, x2, x3) - x)) height = int(math.ceil(max(y0, y1, y2, y3) - y)) img = image.get_a1_from_tiff(filename, img.tiff_page, img.rotated if img.rotated else False) # Not sure if this is correct for A1 ... probably not assert(format == cairo.FORMAT_RGB24) surf = cairo.ImageSurface(format, width, height) cr = cairo.Context(surf) cr.set_source_rgb(1, 1, 1) cr.paint() cr.set_source_surface(img, -x, -y) cr.paint() return surf class ImageWriter: def __init__(self, path, prefix): # I am not qutie sure whether I like the params here. self.count = 0 self.path = path self.prefix = prefix # Create directory if it does not exists. Assumes only one level # is missing. # In case the prefix contains further path components real_path = os.path.dirname(os.path.join(self.path, self.prefix)) if not os.path.exists(real_path): os.mkdir(real_path) def output_area(self, img, filename, x, y, width, height): surf = get_box_surface(img, filename, x, y, width, height) filename = "%s%04d.png" % (self.prefix, self.count) full_path = os.path.join(self.path, filename) surf.write_to_png(full_path) self.count += 1 return filename def output_box(self, box): img = box.sheet.get_page_image(box.question.page_number) filename = box.question.questionnaire.survey.path(img.filename) return self.output_area(img, filename, box.data.x, box.data.y, box.data.width, box.data.height) def output_boxes(self, boxes, real=False, padding=5): x1 = 99999 y1 = 99999 x2 = 0 y2 = 0 img = boxes[0].sheet.get_page_image(boxes[0].question.page_number) filename = boxes[0].question.questionnaire.survey.path(img.filename) for box in boxes: if real: pos = box.data else: pos = box x1 = min(x1, pos.x) y1 = min(y1, pos.y) x2 = max(x2, pos.x + pos.width) y2 = max(y2, pos.y + pos.height) x1 -= padding y1 -= padding x2 += padding y2 += padding return self.output_area(img, filename, x1, y1, x2 - x1, y2 - y1) sdaps-1.9.8/sdaps/utils/latex.py0000644000175000000660000001444013423053744017350 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, 2013, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from sdaps import log import re from sdaps import defs import subprocess import os try: from sdaps.utils.latexmap import mapping except ImportError: mapping = {} log.warn(_('The latex character map is missing! Please build it using the supplied tool (create-latexmap.py).')) # Add some more mappings # NBSP mapping['~'] = ' ' re_latex_to_unicode_mapping = {} for token, replacement in mapping.items(): regexp = re.compile('%s(?=^w|})' % re.escape(token)) re_latex_to_unicode_mapping[regexp] = replacement # Regular expressions don't work really, but we replace a single string anyways unicode_to_latex_mapping = {} for token, replacement in mapping.items(): unicode_to_latex_mapping[replacement] = "{%s}" % token def latex_to_unicode(string): string = str(string) for regexp, replacement in re_latex_to_unicode_mapping.items(): string, count = regexp.subn(replacement, string) def ret_char(match): return match.group('char') string, count = re.subn(r'\\IeC {(?P.*?)}', ret_char, string) return string def unicode_to_latex(string): string = str(string) for char, replacement in unicode_to_latex_mapping.items(): string = string.replace(char, replacement) # The returned string may still contain unicode characters if # the user is using xelatex. But in that case, the remapping is not # needed anyway. # However, it could also mean that the mapping needs to be updated. try: string.encode('ascii') except UnicodeEncodeError: log.warn(_("Generated string for LaTeX contains unicode characters. This may not work correctly and could mean the LaTeX character map needs to be updated.")) return string def quote_braces(string): return string.replace('{', '\\{').replace('}', '\\}') def write_override(survey, optfile, draft=False, questionnaire_ids=None): latex_override = open(optfile, 'w') if questionnaire_ids: quoted_ids = [quote_braces(str(id)) for id in questionnaire_ids] else: quoted_ids = [] latex_override.write(''' %% This file exists to force the latex document into "final" mode. %% It is parsed after the setup phase of the SDAPS class. %% Old class vs. new class \\ifcsname @PAGEMARKtrue\endcsname \\setcounter{surveyidlshw}{%(survey_id_lshw)i} \\setcounter{surveyidmshw}{%(survey_id_mshw)i} \\def\\surveyid{%(survey_id)i} %(noglobalid)s\\def\\globalid{%(global_id)s} \\@STAMPtrue \\@PAGEMARKtrue \\@sdaps@draft%(draft)s \\def\\questionnaireids{%(qids_old)s} \\else \\group_begin: \\def\\setoptions#1#2#3{ \\tl_gset:Nn \\g_sdaps_survey_id_tl { #1 } %(noglobalid)s\\tl_gset:Nn \\g_sdaps_global_id_tl { #2 } \\seq_gset_from_clist:Nn \\g_sdaps_questionnaire_ids_seq { #3 } } \\bool_gset_%(draft)s:N \g_sdaps_draft_bool \\ExplSyntaxOff \\setoptions{%(survey_id)i}{%(global_id)s}{%(qids)s} \\ExplSyntaxOn \group_end: \\fi ''' % { 'survey_id' : survey.survey_id, 'survey_id_lshw' : (survey.survey_id % (2 ** 16)), 'survey_id_mshw' : (survey.survey_id / (2 ** 16)), 'draft' : 'true' if draft else 'false', 'noglobalid' : '%' if draft else '', 'global_id' : quote_braces(survey.global_id) if survey.global_id is not None else '', 'qids_old' : '{' + '},{'.join(quoted_ids) + '}' if quoted_ids else '{NONE}', 'qids' : '{' + '},{'.join(quoted_ids) + '}' if quoted_ids else '{}', }) latex_override.close() # This is a list, because the order is relevant! ascii_to_latex = [ ('{', '\\{'), ('}', '\\}'), ('\\', '{\\textbackslash}'), ('%', '\\%'), ('$', '\\$'), ('_', '\\_'), ('|', '{\\textbar}'), ('>', '{\\textgreater}'), ('<', '{\\textless}'), ('&', '\\&'), ('#', '\#'), ('^', '\\^{}'), ('~', '\\~{}'), ('"', '\\"{}'), ] def raw_unicode_to_latex(string): """In addition to converting all unicode characters to LaTeX expressions this function also replaces some characters like newlines with their LaTeX equvivalent.""" # We need to quote any special character (or replace it) for char, replacement in ascii_to_latex: string = string.replace(char, replacement) string = unicode_to_latex(string) string = str(string) # Replace many newlines with a paragraph marker string, count = re.subn('\n\n+', '\u2029', string, flags=re.MULTILINE) # Replace single newline with \\+newline string = string.replace('\n', '\\\\\n') # And remove the paragraph marker again (insert two newlines) string = string.replace('\u2029', '\n\n') return string.encode('ascii') def run_engine(engine, texfile, cwd, inputs=[]): def _preexec_fn(): if defs.latex_preexec_hook is not None: defs.latex_preexec_hook() inputs.extend(p for p in os.environ.get('TEXINPUTS', '').split(':') if p not in ['.', '']) if inputs: os.environ['TEXINPUTS'] = ':'.join(['.'] + inputs + ['']) verbose = os.environ.get('VERBOSE', '0') if verbose in ['1', 'y']: mode = 'nonstopmode' else: mode = 'batchmode' subprocess.call([engine, '-halt-on-error', '-interaction', mode, texfile], cwd=cwd, preexec_fn=_preexec_fn) def compile(engine, texfile, cwd, inputs=[]): run_engine(engine, texfile, cwd, inputs) run_engine(engine, texfile, cwd, inputs) run_engine(engine, texfile, cwd, inputs) run_engine(engine, texfile, cwd, inputs) sdaps-1.9.8/sdaps/utils/latexmap.py0000644000175000000660000003474113367301321020046 0ustar benjaminlock00000000000000#This file is auto generated from the latex unicode mapping. #: Mapping from LaTeX commands to unicode characters. mapping = { u'\\nobreakspace': u'\u00A0', u'\\textexclamdown': u'\u00A1', u'\\textcent': u'\u00A2', u'\\textsterling': u'\u00A3', u'\\textcurrency': u'\u00A4', u'\\textyen': u'\u00A5', u'\\textbrokenbar': u'\u00A6', u'\\textsection': u'\u00A7', u'\\textasciidieresis': u'\u00A8', u'\\textcopyright': u'\u00A9', u'\\textordfeminine': u'\u00AA', u'\\guillemotleft': u'\u00AB', u'\\textlnot': u'\u00AC', u'\\-': u'\u00AD', u'\\textregistered': u'\u00AE', u'\\textasciimacron': u'\u00AF', u'\\textdegree': u'\u00B0', u'\\textpm': u'\u00B1', u'\\texttwosuperior': u'\u00B2', u'\\textthreesuperior': u'\u00B3', u'\\textasciiacute': u'\u00B4', u'\\textmu': u'\u00B5', u'\\textparagraph': u'\u00B6', u'\\textperiodcentered': u'\u00B7', u'\\c\\ ': u'\u00B8', u'\\textonesuperior': u'\u00B9', u'\\textordmasculine': u'\u00BA', u'\\guillemotright': u'\u00BB', u'\\textonequarter': u'\u00BC', u'\\textonehalf': u'\u00BD', u'\\textthreequarters': u'\u00BE', u'\\textquestiondown': u'\u00BF', u'\\`A': u'\u00C0', u'\\\'A': u'\u00C1', u'\\^A': u'\u00C2', u'\\~A': u'\u00C3', u'\\"A': u'\u00C4', u'\\r A': u'\u00C5', u'\\AE': u'\u00C6', u'\\c C': u'\u00C7', u'\\`E': u'\u00C8', u'\\\'E': u'\u00C9', u'\\^E': u'\u00CA', u'\\"E': u'\u00CB', u'\\`I': u'\u00CC', u'\\\'I': u'\u00CD', u'\\^I': u'\u00CE', u'\\"I': u'\u00CF', u'\\DH': u'\u00D0', u'\\~N': u'\u00D1', u'\\`O': u'\u00D2', u'\\\'O': u'\u00D3', u'\\^O': u'\u00D4', u'\\~O': u'\u00D5', u'\\"O': u'\u00D6', u'\\texttimes': u'\u00D7', u'\\O': u'\u00D8', u'\\`U': u'\u00D9', u'\\\'U': u'\u00DA', u'\\^U': u'\u00DB', u'\\"U': u'\u00DC', u'\\\'Y': u'\u00DD', u'\\TH': u'\u00DE', u'\\ss': u'\u00DF', u'\\`a': u'\u00E0', u'\\\'a': u'\u00E1', u'\\^a': u'\u00E2', u'\\~a': u'\u00E3', u'\\"a': u'\u00E4', u'\\r a': u'\u00E5', u'\\ae': u'\u00E6', u'\\c c': u'\u00E7', u'\\`e': u'\u00E8', u'\\\'e': u'\u00E9', u'\\^e': u'\u00EA', u'\\"e': u'\u00EB', u'\\`\\i': u'\u00EC', u'\\\'\\i': u'\u00ED', u'\\^\\i': u'\u00EE', u'\\"\\i': u'\u00EF', u'\\dh': u'\u00F0', u'\\~n': u'\u00F1', u'\\`o': u'\u00F2', u'\\\'o': u'\u00F3', u'\\^o': u'\u00F4', u'\\~o': u'\u00F5', u'\\"o': u'\u00F6', u'\\textdiv': u'\u00F7', u'\\o': u'\u00F8', u'\\`u': u'\u00F9', u'\\\'u': u'\u00FA', u'\\^u': u'\u00FB', u'\\"u': u'\u00FC', u'\\\'y': u'\u00FD', u'\\th': u'\u00FE', u'\\"y': u'\u00FF', u'\\=A': u'\u0100', u'\\=a': u'\u0101', u'\\u A': u'\u0102', u'\\u a': u'\u0103', u'\\k A': u'\u0104', u'\\k a': u'\u0105', u'\\\'C': u'\u0106', u'\\\'c': u'\u0107', u'\\^C': u'\u0108', u'\\^c': u'\u0109', u'\\.C': u'\u010A', u'\\.c': u'\u010B', u'\\v C': u'\u010C', u'\\v c': u'\u010D', u'\\v D': u'\u010E', u'\\v d': u'\u010F', u'\\DJ': u'\u0110', u'\\dj': u'\u0111', u'\\=E': u'\u0112', u'\\=e': u'\u0113', u'\\u E': u'\u0114', u'\\u e': u'\u0115', u'\\.E': u'\u0116', u'\\.e': u'\u0117', u'\\k E': u'\u0118', u'\\k e': u'\u0119', u'\\v E': u'\u011A', u'\\v e': u'\u011B', u'\\^G': u'\u011C', u'\\^g': u'\u011D', u'\\u G': u'\u011E', u'\\u g': u'\u011F', u'\\.G': u'\u0120', u'\\.g': u'\u0121', u'\\c G': u'\u0122', u'\\c g': u'\u0123', u'\\^H': u'\u0124', u'\\^h': u'\u0125', u'\\~I': u'\u0128', u'\\~\\i': u'\u0129', u'\\=I': u'\u012A', u'\\=\\i': u'\u012B', u'\\u I': u'\u012C', u'\\u\\i': u'\u012D', u'\\k I': u'\u012E', u'\\k\\i': u'\u012F', u'\\.I': u'\u0130', u'\\i': u'\u0131', u'\\IJ': u'\u0132', u'\\ij': u'\u0133', u'\\^J': u'\u0134', u'\\^\\j': u'\u0135', u'\\c K': u'\u0136', u'\\c k': u'\u0137', u'\\\'L': u'\u0139', u'\\\'l': u'\u013A', u'\\c L': u'\u013B', u'\\c l': u'\u013C', u'\\v L': u'\u013D', u'\\v l': u'\u013E', u'\\L': u'\u0141', u'\\l': u'\u0142', u'\\\'N': u'\u0143', u'\\\'n': u'\u0144', u'\\c N': u'\u0145', u'\\c n': u'\u0146', u'\\v N': u'\u0147', u'\\v n': u'\u0148', u'\\NG': u'\u014A', u'\\ng': u'\u014B', u'\\=O': u'\u014C', u'\\=o': u'\u014D', u'\\u O': u'\u014E', u'\\u o': u'\u014F', u'\\H O': u'\u0150', u'\\H o': u'\u0151', u'\\OE': u'\u0152', u'\\oe': u'\u0153', u'\\\'R': u'\u0154', u'\\\'r': u'\u0155', u'\\c R': u'\u0156', u'\\c r': u'\u0157', u'\\v R': u'\u0158', u'\\v r': u'\u0159', u'\\\'S': u'\u015A', u'\\\'s': u'\u015B', u'\\^S': u'\u015C', u'\\^s': u'\u015D', u'\\c S': u'\u015E', u'\\c s': u'\u015F', u'\\v S': u'\u0160', u'\\v s': u'\u0161', u'\\c T': u'\u0162', u'\\c t': u'\u0163', u'\\v T': u'\u0164', u'\\v t': u'\u0165', u'\\~U': u'\u0168', u'\\~u': u'\u0169', u'\\=U': u'\u016A', u'\\=u': u'\u016B', u'\\u U': u'\u016C', u'\\u u': u'\u016D', u'\\r U': u'\u016E', u'\\r u': u'\u016F', u'\\H U': u'\u0170', u'\\H u': u'\u0171', u'\\k U': u'\u0172', u'\\k u': u'\u0173', u'\\^W': u'\u0174', u'\\^w': u'\u0175', u'\\^Y': u'\u0176', u'\\^y': u'\u0177', u'\\"Y': u'\u0178', u'\\\'Z': u'\u0179', u'\\\'z': u'\u017A', u'\\.Z': u'\u017B', u'\\.z': u'\u017C', u'\\v Z': u'\u017D', u'\\v z': u'\u017E', u'\\textflorin': u'\u0192', u'\\v A': u'\u01CD', u'\\v a': u'\u01CE', u'\\v I': u'\u01CF', u'\\v \\i': u'\u01D0', u'\\v O': u'\u01D1', u'\\v o': u'\u01D2', u'\\v U': u'\u01D3', u'\\v u': u'\u01D4', u'\\=\\AE': u'\u01E2', u'\\=\\ae': u'\u01E3', u'\\v G': u'\u01E6', u'\\v g': u'\u01E7', u'\\v K': u'\u01E8', u'\\v k': u'\u01E9', u'\\k O': u'\u01EA', u'\\k o': u'\u01EB', u'\\v\\j': u'\u01F0', u'\\\'G': u'\u01F4', u'\\\'g': u'\u01F5', u'\\textcommabelow S': u'\u0218', u'\\textcommabelow s': u'\u0219', u'\\textcommabelow T': u'\u021A', u'\\textcommabelow t': u'\u021B', u'\\=Y': u'\u0232', u'\\=y': u'\u0233', u'\\textasciicircum': u'\u02C6', u'\\textasciicaron': u'\u02C7', u'\\textasciitilde': u'\u02DC', u'\\textasciibreve': u'\u02D8', u'\\textacutedbl': u'\u02DD', u'\\`\\CYRE': u'\u0400', u'\\CYRYO': u'\u0401', u'\\CYRDJE': u'\u0402', u'\\\'\\CYRG': u'\u0403', u'\\CYRIE': u'\u0404', u'\\CYRDZE': u'\u0405', u'\\CYRII': u'\u0406', u'\\CYRYI': u'\u0407', u'\\CYRJE': u'\u0408', u'\\CYRLJE': u'\u0409', u'\\CYRNJE': u'\u040A', u'\\CYRTSHE': u'\u040B', u'\\\'\\CYRK': u'\u040C', u'\\`\\CYRI': u'\u040D', u'\\CYRUSHRT': u'\u040E', u'\\CYRDZHE': u'\u040F', u'\\CYRA': u'\u0410', u'\\CYRB': u'\u0411', u'\\CYRV': u'\u0412', u'\\CYRG': u'\u0413', u'\\CYRD': u'\u0414', u'\\CYRE': u'\u0415', u'\\CYRZH': u'\u0416', u'\\CYRZ': u'\u0417', u'\\CYRI': u'\u0418', u'\\CYRISHRT': u'\u0419', u'\\CYRK': u'\u041A', u'\\CYRL': u'\u041B', u'\\CYRM': u'\u041C', u'\\CYRN': u'\u041D', u'\\CYRO': u'\u041E', u'\\CYRP': u'\u041F', u'\\CYRR': u'\u0420', u'\\CYRS': u'\u0421', u'\\CYRT': u'\u0422', u'\\CYRU': u'\u0423', u'\\CYRF': u'\u0424', u'\\CYRH': u'\u0425', u'\\CYRC': u'\u0426', u'\\CYRCH': u'\u0427', u'\\CYRSH': u'\u0428', u'\\CYRSHCH': u'\u0429', u'\\CYRHRDSN': u'\u042A', u'\\CYRERY': u'\u042B', u'\\CYRSFTSN': u'\u042C', u'\\CYREREV': u'\u042D', u'\\CYRYU': u'\u042E', u'\\CYRYA': u'\u042F', u'\\cyra': u'\u0430', u'\\cyrb': u'\u0431', u'\\cyrv': u'\u0432', u'\\cyrg': u'\u0433', u'\\cyrd': u'\u0434', u'\\cyre': u'\u0435', u'\\cyrzh': u'\u0436', u'\\cyrz': u'\u0437', u'\\cyri': u'\u0438', u'\\cyrishrt': u'\u0439', u'\\cyrk': u'\u043A', u'\\cyrl': u'\u043B', u'\\cyrm': u'\u043C', u'\\cyrn': u'\u043D', u'\\cyro': u'\u043E', u'\\cyrp': u'\u043F', u'\\cyrr': u'\u0440', u'\\cyrs': u'\u0441', u'\\cyrt': u'\u0442', u'\\cyru': u'\u0443', u'\\cyrf': u'\u0444', u'\\cyrh': u'\u0445', u'\\cyrc': u'\u0446', u'\\cyrch': u'\u0447', u'\\cyrsh': u'\u0448', u'\\cyrshch': u'\u0449', u'\\cyrhrdsn': u'\u044A', u'\\cyrery': u'\u044B', u'\\cyrsftsn': u'\u044C', u'\\cyrerev': u'\u044D', u'\\cyryu': u'\u044E', u'\\cyrya': u'\u044F', u'\\`\\cyre': u'\u0450', u'\\cyryo': u'\u0451', u'\\cyrdje': u'\u0452', u'\\\'\\cyrg': u'\u0453', u'\\cyrie': u'\u0454', u'\\cyrdze': u'\u0455', u'\\cyrii': u'\u0456', u'\\cyryi': u'\u0457', u'\\cyrje': u'\u0458', u'\\cyrlje': u'\u0459', u'\\cyrnje': u'\u045A', u'\\cyrtshe': u'\u045B', u'\\\'\\cyrk': u'\u045C', u'\\`\\cyri': u'\u045D', u'\\cyrushrt': u'\u045E', u'\\cyrdzhe': u'\u045F', u'\\CYRYAT': u'\u0462', u'\\cyryat': u'\u0463', u'\\CYRBYUS': u'\u046A', u'\\cyrbyus': u'\u046B', u'\\CYRFITA': u'\u0472', u'\\cyrfita': u'\u0473', u'\\CYRIZH': u'\u0474', u'\\cyrizh': u'\u0475', u'\\C\\CYRIZH': u'\u0476', u'\\C\\cyrizh': u'\u0477', u'\\CYRSEMISFTSN': u'\u048C', u'\\cyrsemisftsn': u'\u048D', u'\\CYRRTICK': u'\u048E', u'\\cyrrtick': u'\u048F', u'\\CYRGUP': u'\u0490', u'\\cyrgup': u'\u0491', u'\\CYRGHCRS': u'\u0492', u'\\cyrghcrs': u'\u0493', u'\\CYRGHK': u'\u0494', u'\\cyrghk': u'\u0495', u'\\CYRZHDSC': u'\u0496', u'\\cyrzhdsc': u'\u0497', u'\\CYRZDSC': u'\u0498', u'\\cyrzdsc': u'\u0499', u'\\CYRKDSC': u'\u049A', u'\\cyrkdsc': u'\u049B', u'\\CYRKVCRS': u'\u049C', u'\\cyrkvcrs': u'\u049D', u'\\CYRKHCRS': u'\u049E', u'\\cyrkhcrs': u'\u049F', u'\\CYRKBEAK': u'\u04A0', u'\\cyrkbeak': u'\u04A1', u'\\CYRNDSC': u'\u04A2', u'\\cyrndsc': u'\u04A3', u'\\CYRNG': u'\u04A4', u'\\cyrng': u'\u04A5', u'\\CYRPHK': u'\u04A6', u'\\cyrphk': u'\u04A7', u'\\CYRABHHA': u'\u04A8', u'\\cyrabhha': u'\u04A9', u'\\CYRSDSC': u'\u04AA', u'\\cyrsdsc': u'\u04AB', u'\\CYRTDSC': u'\u04AC', u'\\cyrtdsc': u'\u04AD', u'\\CYRY': u'\u04AE', u'\\cyry': u'\u04AF', u'\\CYRYHCRS': u'\u04B0', u'\\cyryhcrs': u'\u04B1', u'\\CYRHDSC': u'\u04B2', u'\\cyrhdsc': u'\u04B3', u'\\CYRTETSE': u'\u04B4', u'\\cyrtetse': u'\u04B5', u'\\CYRCHRDSC': u'\u04B6', u'\\cyrchrdsc': u'\u04B7', u'\\CYRCHVCRS': u'\u04B8', u'\\cyrchvcrs': u'\u04B9', u'\\CYRSHHA': u'\u04BA', u'\\cyrshha': u'\u04BB', u'\\CYRABHCH': u'\u04BC', u'\\cyrabhch': u'\u04BD', u'\\CYRABHCHDSC': u'\u04BE', u'\\cyrabhchdsc': u'\u04BF', u'\\CYRpalochka': u'\u04C0', u'\\U\\CYRZH': u'\u04C1', u'\\U\\cyrzh': u'\u04C2', u'\\CYRKHK': u'\u04C3', u'\\cyrkhk': u'\u04C4', u'\\CYRLDSC': u'\u04C5', u'\\cyrldsc': u'\u04C6', u'\\CYRNHK': u'\u04C7', u'\\cyrnhk': u'\u04C8', u'\\CYRCHLDSC': u'\u04CB', u'\\cyrchldsc': u'\u04CC', u'\\CYRMDSC': u'\u04CD', u'\\cyrmdsc': u'\u04CE', u'\\U\\CYRA': u'\u04D0', u'\\U\\cyra': u'\u04D1', u'\\"\\CYRA': u'\u04D2', u'\\"\\cyra': u'\u04D3', u'\\CYRAE': u'\u04D4', u'\\cyrae': u'\u04D5', u'\\U\\CYRE': u'\u04D6', u'\\U\\cyre': u'\u04D7', u'\\CYRSCHWA': u'\u04D8', u'\\cyrschwa': u'\u04D9', u'\\"\\CYRSCHWA': u'\u04DA', u'\\"\\cyrschwa': u'\u04DB', u'\\"\\CYRZH': u'\u04DC', u'\\"\\cyrzh': u'\u04DD', u'\\"\\CYRZ': u'\u04DE', u'\\"\\cyrz': u'\u04DF', u'\\CYRABHDZE': u'\u04E0', u'\\cyrabhdze': u'\u04E1', u'\\=\\CYRI': u'\u04E2', u'\\=\\cyri': u'\u04E3', u'\\"\\CYRI': u'\u04E4', u'\\"\\cyri': u'\u04E5', u'\\"\\CYRO': u'\u04E6', u'\\"\\cyro': u'\u04E7', u'\\CYROTLD': u'\u04E8', u'\\cyrotld': u'\u04E9', u'\\"\\CYREREV': u'\u04EC', u'\\"\\cyrerev': u'\u04ED', u'\\=\\CYRU': u'\u04EE', u'\\=\\cyru': u'\u04EF', u'\\"\\CYRU': u'\u04F0', u'\\"\\cyru': u'\u04F1', u'\\H\\CYRU': u'\u04F2', u'\\H\\cyru': u'\u04F3', u'\\"\\CYRCH': u'\u04F4', u'\\"\\cyrch': u'\u04F5', u'\\CYRGDSC': u'\u04F6', u'\\cyrgdsc': u'\u04F7', u'\\"\\CYRERY': u'\u04F8', u'\\"\\cyrery': u'\u04F9', u'\\CYRGDSCHCRS': u'\u04FA', u'\\cyrgdschcrs': u'\u04FB', u'\\CYRHHK': u'\u04FC', u'\\cyrhhk': u'\u04FD', u'\\CYRHHCRS': u'\u04FE', u'\\cyrhhcrs': u'\u04FF', u'\\textbaht': u'\u0E3F', u'\\.B': u'\u1E02', u'\\.b': u'\u1E03', u'\\textcompwordmark': u'\u200C', u'-': u'\u2010', u'\\mbox{-': u'\u2011', u'\\textendash': u'\u2012', u'\\textendash': u'\u2013', u'\\textemdash': u'\u2014', u'\\textemdash': u'\u2015', u'\\textbardbl': u'\u2016', u'\\textquoteleft': u'\u2018', u'\\textquoteright': u'\u2019', u'\\quotesinglbase': u'\u201A', u'\\textquotedblleft': u'\u201C', u'\\textquotedblright': u'\u201D', u'\\quotedblbase': u'\u201E', u'\\textdagger': u'\u2020', u'\\textdaggerdbl': u'\u2021', u'\\textbullet': u'\u2022', u'\\textellipsis': u'\u2026', u'\\textperthousand': u'\u2030', u'\\textpertenthousand': u'\u2031', u'\\guilsinglleft': u'\u2039', u'\\guilsinglright': u'\u203A', u'\\textreferencemark': u'\u203B', u'\\textinterrobang': u'\u203D', u'\\textfractionsolidus': u'\u2044', u'\\textasteriskcentered': u'\u204E', u'\\textdiscount': u'\u2052', u'\\textcolonmonetary': u'\u20A1', u'\\textlira': u'\u20A4', u'\\textnaira': u'\u20A6', u'\\textwon': u'\u20A9', u'\\textdong': u'\u20AB', u'\\texteuro': u'\u20AC', u'\\textpeso': u'\u20B1', u'\\textcelsius': u'\u2103', u'\\textnumero': u'\u2116', u'\\textcircledP': u'\u2117', u'\\textrecipe': u'\u211E', u'\\textservicemark': u'\u2120', u'\\texttrademark': u'\u2122', u'\\textohm': u'\u2126', u'\\textmho': u'\u2127', u'\\textestimated': u'\u212E', u'\\textleftarrow': u'\u2190', u'\\textuparrow': u'\u2191', u'\\textrightarrow': u'\u2192', u'\\textdownarrow': u'\u2193', u'\\textlangle': u'\u2329', u'\\textrangle': u'\u232A', u'\\textblank': u'\u2422', u'\\textvisiblespace': u'\u2423', u'\\textopenbullet': u'\u25E6', u'\\textbigcircle': u'\u25EF', u'\\textmusicalnote': u'\u266A', u'\\=G': u'\u1E20', u'\\=g': u'\u1E21', u'\\ifhmode\\nobreak\\fi': u'\uFEFF' } sdaps-1.9.8/sdaps/utils/mimetype.py0000644000175000000660000000241013367301321020050 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or #(at your option) any later version # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import subprocess def mimetype(filename): '''return the mimetype of the file as string or an error string, if the file does not exist or is not accesible. ''' file = subprocess.Popen( ['file', '--brief', '--mime-type', filename], stdout=subprocess.PIPE, stderr=subprocess.PIPE ) stdout, stderr = file.communicate() if stdout: stdout = stdout.strip() return stdout.decode('ascii') sdaps-1.9.8/sdaps/utils/opencv.py0000644000175000000660000002143313405476454017534 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2013, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import os.path import errno import cv2 import numpy as np from sdaps import image import cairo from sdaps import defs from sdaps import log from sdaps.utils.ugettext import ugettext, ungettext _ = ugettext try: import gi gi.require_version('Poppler', '0.18') from gi.repository import Poppler, Gio except: log.warn(_("Cannot convert PDF files as poppler is not installed or usable!")) def iter_images_and_pages(images): """This function iterates over a images and also the contained pages. As OpenCV is not able to handle multipage TIFF files, we use the SDAPS internal loading method for those.""" for filename in images: if not os.path.exists(filename): raise IOError(errno.ENOENT, _("File does not exist"), filename) pages = 1 is_tiff = False is_pdf = False try: # Check whether this is a TIFF file (ie. try to retrieve the page count) pages = image.get_tiff_page_count(filename) is_tiff = True except AssertionError: pass if not is_tiff: try: gfile = Gio.File.new_for_path(filename) pdf_doc = Poppler.Document.new_from_gfile(gfile, None, None) pages = pdf_doc.get_n_pages() is_pdf = True except: # Either not PDF/damaged or poppler not installed properly pass for page in range(pages): if is_tiff: # TIFF pages are zero based surf = image.get_rgb24_from_tiff(filename, page, False) img = to_opencv(surf) elif is_pdf: # Try to retrieve a single fullpage image, if that fails, render # document at 300dpi. THRESH = 10 #pt pdfpage = pdf_doc.get_page(page) page_width, page_height = pdfpage.get_size() images = pdfpage.get_image_mapping() if len(images) == 1 and ( abs(images[0].area.x1) < THRESH and abs(images[0].area.y1) < THRESH and abs(images[0].area.x2 - page_width) < THRESH and abs(images[0].area.y2 - page_height) < THRESH): # Assume one full page image, and simply use that. surf = pdfpage.get_image(images[0].image_id) else: dpi = 0 # Try to detect the DPI of the scan for img in images: if img.area.y2 - img.area.y1 < page_height / 2: continue surf = pdfpage.get_image(img.image_id) # Calculate DPI from height dpi_x = round(surf.get_height() / (img.area.y2 - img.area.y1) * 72) dpi_y = round(surf.get_width() / (img.area.x2 - img.area.x1) * 72) if abs(dpi_x - dpi_y) <= 1: dpi = max(dpi, dpi_x, dpi_y) # Fall back to 300dpi for odd values if dpi < 199 or dpi > 601: dpi = 300 surf = cairo.ImageSurface(cairo.FORMAT_RGB24, int(dpi / 72 * page_width), int(dpi / 72 * page_height)) cr = cairo.Context(surf) cr.scale(dpi / 72, dpi / 72) cr.set_source_rgb(1, 1, 1) cr.paint() pdfpage.render_for_printing(cr) del cr img = to_opencv(surf) else: img = cv2.imread(filename) yield img, filename, page def sharpen(img): blured = cv2.GaussianBlur(img, (0,0), 5) img = cv2.addWeighted(img, 1.5, blured, -0.5, 0) return img def to_opencv(surf): width = surf.get_width() height = surf.get_height() stride = surf.get_stride() # We need to ensure a sane stride! np_width = stride // 4 # This converts by doing a copy; first create target numpy array # We need a dummy alpha channel ... target = np.empty((height, np_width), dtype=np.uint32) tmp_surf = cairo.ImageSurface.create_for_data(target.data, cairo.FORMAT_RGB24, width, height, stride) cr = cairo.Context(tmp_surf) # Handle A1 surfaces? cr.set_source_surface(surf) cr.paint() del cr tmp_surf.flush() del tmp_surf # Now, we need a bit of reshaping img = np.empty((height, width, 3), dtype=np.uint8) # order should be BGR img[:,:,2] = 0xff & (target[:,:] >> 16) img[:,:,1] = 0xff & (target[:,:] >> 8) img[:,:,0] = 0xff & target[:,:] return img def to_a1_surf(img): # Assume that x is the second position assert(len(img.strides) == 2) assert(img.strides[1] == 1) if img.strides[0] % 4: # Need to reshape, lets just cut off up to 3 pixel target = np.empty((img.shape[0], img.shape[1] - img.shape[1] % 4), dtype=np.uint8) target[:,:] = img[:,:target.shape[1]] img = target height, width = img.shape surf_a8 = cairo.ImageSurface.create_for_data(img.data, cairo.FORMAT_A8, width, height, img.strides[0]) surf_a1 = cairo.ImageSurface(cairo.FORMAT_A1, width, height) cr = cairo.Context(surf_a1) cr.set_operator(cairo.OPERATOR_SOURCE) cr.set_source_surface(surf_a8) cr.paint() return surf_a1 def ensure_orientation(img, portrait): img_portrait = img.shape[1] <= img.shape[0] if img_portrait != portrait: # Rotate into new array (CV does not like negative strides and such) new = np.empty((img.shape[1],img.shape[0])+img.shape[2:], dtype=img.dtype) new[:] = np.rot90(img) img = new return img def ensure_greyscale(img): if len(img.shape) == 2: # Well, seems to be greyscale/monochrome already return img # Average the color samples, and convert back to uint8 img = np.average(img, 2) img = np.array(img, dtype=np.uint8) return img def convert_to_monochrome(img, size=201, thresh_adjust=5): img = ensure_greyscale(img) img = cv2.adaptiveThreshold(img, 255.0, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, size, thresh_adjust) return img def save(img, filename): cv2.imwrite(img, filename) def _fallback_matrix(width, height, paper_width, paper_height): """Calcualte a fallback matrix. Basically the same as in matrix.py, should be merged somehow!""" xres = width / float(paper_width) yres = height / float(paper_height) # Assume the smaller size fits better ... res = min(xres, yres) scan_width = width / res scan_height = height / res dx = (paper_width - scan_width) / 2.0 dy = (paper_height - scan_height) / 2.0 matrix = cairo.Matrix() # Center the image matrix.translate(dx, dy) matrix.scale(1.0 / res, 1.0 / res) matrix.invert() return matrix, res def transform_using_corners(img, paper_width, paper_height): surf = to_a1_surf(convert_to_monochrome(img)) matrix, res = _fallback_matrix(surf.get_width(), surf.get_height(), paper_width, paper_height) top_left = image.find_corner_marker(surf, matrix, 1) top_right = image.find_corner_marker(surf, matrix, 2) bottom_right = image.find_corner_marker(surf, matrix, 3) bottom_left = image.find_corner_marker(surf, matrix, 4) scale = 1 * res x0 = scale * defs.corner_mark_left y0 = scale * defs.corner_mark_top x1 = scale * (paper_width - defs.corner_mark_right) y1 = scale * (paper_height - defs.corner_mark_bottom) width, height = int(scale * paper_width), int(scale * paper_height) # Increase width to be a multiple of 4 if width % 4: width = width + 4 - width % 4 transform_matrix = cv2.getPerspectiveTransform( np.array((top_left, top_right, bottom_right, bottom_left), dtype=np.float32), np.array(((x0, y0), (x1, y0), (x1, y1), (x0, y1)), dtype=np.float32)) transformed = cv2.warpPerspective(img, transform_matrix, dsize=(width, height)) return transformed sdaps-1.9.8/sdaps/utils/paper.py0000644000175000000660000000460113367301321017332 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2013, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . _fallback = "A4", (210., 297.) def _get_gtk_ppd_papersize(paper=None): try: import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk except: return paper, None else: def _find_papersize_by_ppd_name(paper=None): if not paper: return None paper = paper.lower() for papersize in Gtk.PaperSize.get_paper_sizes(False): if paper == papersize.get_ppd_name().lower(): return papersize papersize = _find_papersize_by_ppd_name(paper) if papersize is None: # Retrieve default paper size paper_name = Gtk.PaperSize.get_default() papersize = Gtk.PaperSize.new(paper_name) width = papersize.get_width(Gtk.Unit.MM) height = papersize.get_height(Gtk.Unit.MM) return papersize.get_ppd_name(), (width, height) def get_tex_papersize(paper=None): # Assume that the name is the PPD name in lowercase + 'paper' paper, size = _get_gtk_ppd_papersize(paper) if paper is None: paper = _fallback[0] return paper.lower() + 'paper' def get_reportlab_papersize(paper=None): paper, size = _get_gtk_ppd_papersize(paper) if size: size = (size[0] / 25.4 * 72.0, size[1] / 25.4 * 72.0) if size is None: if paper: from reportlab.lib import pagesizes if hasattr(pagesizes, paper.upper()): size = getattr(pagesizes, paper.upper()) if size is None: size = (_fallback[1][0] / 25.4 * 72.0, _fallback[1][1] / 25.4 * 72.0) return size sdaps-1.9.8/sdaps/utils/ugettext.py0000644000175000000660000000234513367301321020077 0ustar benjaminlock00000000000000# -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright(C) 2008, Christoph Simon # Copyright(C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import gettext def ugettext(string): '''gettext for unicode objects ''' translation = gettext.gettext(string.encode('UTF-8')).decode('UTF-8') return translation.split('|', 1)[-1] def ungettext(singular, plural, n): '''ngettext for unicode objects ''' return gettext.ngettext( singular.encode('UTF-8'), plural.encode('UTF-8'), n).decode('UTF-8') sdaps-1.9.8/sdaps.py0000755000175000000660000000165413367301321015073 0ustar benjaminlock00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # SDAPS - Scripts for data acquisition with paper based surveys # Copyright (C) 2008, Christoph Simon # Copyright (C) 2008, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import sys import sdaps sys.exit(sdaps.main(local_run = True)) sdaps-1.9.8/setup.cfg0000644000175000000660000000044213346275473015236 0ustar benjaminlock00000000000000[build] icons=False help=False i18n=True [build_i18n] domain=sdaps #desktop_files=[("share/applications", ("data/update-manager.desktop.in",))] #schemas_files=[("share/gconf/schemas", ("data/update-manager.schemas.in",))] #desktop_files=[("share/sdaps/tex", ('tex/tex_translations.in',))] sdaps-1.9.8/setup.py0000755000175000000660000002104413611116355015117 0ustar benjaminlock00000000000000#!/usr/bin/env python3 # SDAPS - Scripts for data acquisition with paper based surveys # Copyright (C) 2008, Christoph Simon # Copyright (C) 2008-2013, Benjamin Berg # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from distutils.core import setup from distutils.extension import Extension import glob import os import os.path import subprocess import sys from distutils.command import build from DistUtilsExtra.command import * import configparser # We import sdaps to grab the version number; a bit of a hack but # it should work just fine as few modules are actually loaded by doing # this from sdaps import __version__ def pkgconfig(*packages, **kw): flag_map = {'-I': 'include_dirs', '-L': 'library_dirs', '-l': 'libraries', '-D' : 'define_macros'} (status, tokens) = subprocess.getstatusoutput("pkg-config --libs --cflags %s" % ' '.join(packages)) if status != 0: print(tokens) sys.exit(1) for token in tokens.split(): type = flag_map.get(token[:2]) value = token[2:] if type == 'define_macros': value = tuple(value.split('=', 1)) if type is None: value = token type = 'extra_compile_args' kw.setdefault(type, []).append(value) return kw class sdaps_build_tex(build.build): description = "build and install the LaTeX packages and classes" # Hardcoded ... tex_installdir = 'share/sdaps/tex' tex_resultdir = 'tex/class/build/local' def run(self): # Build the LaTeX packages and classes, note that they cannot build # out of tree currently. maindir = os.path.abspath(os.curdir) if not os.path.exists('tex/class/build.lua'): print('error: LaTeX build script is not available') print('Did you forget to checkout the git submodule? See README for more information.') os._exit(1) os.chdir('tex/class') self.spawn(['./build.lua', 'unpack']) os.chdir(maindir) files = [os.path.join(self.tex_resultdir, f) for f in os.listdir(self.tex_resultdir)] self.distribution.data_files.append((self.tex_installdir, files)) class sdaps_build_i18n(build_i18n.build_i18n): # Hardcoded ... dict_sourcefile = 'tex/tex_translations.in' dict_dir = 'share/sdaps/tex' dict_filename = 'tex_translations' def run(self): # run the original code build_i18n.build_i18n.run(self) dest_dir = os.path.join('build', self.dict_dir) tex_translations = os.path.join(dest_dir, self.dict_filename) # Build the tex_translations file if not os.path.isdir(dest_dir): os.makedirs(dest_dir) cmd = ['intltool-merge', '-d', 'tex/po', self.dict_sourcefile, tex_translations] self.spawn(cmd) ################### # Now build the LaTeX dictionaries def extract_key_lang(key): if not key.endswith(']'): return key, None index = key.rfind('[') return key[:index], key[index+1:-1] parser = configparser.ConfigParser() parser.read(tex_translations) langs = {} keys = set() for k, v in parser.items("translations"): key, lang = extract_key_lang(k) if not key == 'tex-language': keys.add(key) continue assert lang not in langs assert v not in list(langs.items()) langs[lang] = v # Load mapping from unicode to LaTeX command name from sdaps.utils.latex import unicode_to_latex dictfiles = [] for lang, name in langs.items(): print('building LaTeX dictionary file for language %s (%s)' % (name, lang if lang else 'C')) dictfiles.append(os.path.join(dest_dir, 'translator-sdaps-dictionary-%s.dict' % name)) f = open(dictfiles[-1], 'w') f.write('% This file is auto-generated from gettext translations (.po files).\n') f.write('% The header of the original file follows for reference:\n') f.write('%\n') for line in open(self.dict_sourcefile).readlines(): if not line.startswith('#'): break f.write('%' + line[1:]) f.write('%\n\n') f.write('\\ProvidesDictionary{translator-sdaps-dictionary}{%s}\n\n' % name) for key in sorted(keys): if lang is not None: k = "%s[%s]" % (key, lang) else: k = key try: value = parser.get("translations", k) except configparser.NoOptionError: value = parser.get("translations", key) value = unicode_to_latex(value) f.write('\\providetranslation{%s}{%s}\n' % (key, value)) # And install the dictionary files self.distribution.data_files.append((self.dict_dir, dictfiles)) class sdaps_clean_i18n(clean_i18n.clean_i18n): dict_dir = 'share/sdaps/tex' dict_filename = "tex_translations" def run(self): # Remove dictionaries directory = os.path.join('build', self.dict_dir) if os.path.isdir(directory): print("removing all LaTeX dictionaries in '%s'" % directory) for filename in os.listdir(directory): if filename.startswith('translator-sdaps-dictionary-'): os.unlink(os.path.join(directory, filename)) fn = os.path.join('build', self.dict_dir, self.dict_filename) if os.path.exists(fn): os.unlink(fn) clean_i18n.clean_i18n.run(self) class sdaps_build(build_extra.build_extra): sub_commands = build_extra.build_extra.sub_commands + [('build_tex', lambda x : True)] setup(name='sdaps', version=__version__, description='Scripts for data acquisition with paper-based surveys', url='http://sdaps.sipsolutions.net', author='Benjamin Berg, Christoph Simon', author_email='benjamin@sipsolutions.net, post@christoph-simon.eu', license='GPL-3', long_description=""" SDAPS is a tool to carry out paper based surveys. You can create machine readable questionnaires using LaTeX. It also provides the tools to later analyse the scanned data, and create a report. """, packages=['sdaps', 'sdaps.add', 'sdaps.annotate', 'sdaps.boxgallery', 'sdaps.cmdline', 'sdaps.cover', 'sdaps.convert', 'sdaps.csvdata', 'sdaps.gui', 'sdaps.image', 'sdaps.model', 'sdaps.recognize', 'sdaps.reorder', 'sdaps.stamp', 'sdaps.report', 'sdaps.reporttex', 'sdaps.reset', 'sdaps.setup', 'sdaps.setuptex', 'sdaps.utils' ], package_dir={'sdaps.gui': 'sdaps/gui'}, scripts=[ 'bin/sdaps', ], ext_modules=[Extension('sdaps.image.image', ['sdaps/image/wrap_image.c', 'sdaps/image/image.c', 'sdaps/image/transform.c', 'sdaps/image/surface.c'], **pkgconfig('py3cairo', 'cairo', 'glib-2.0', libraries=['tiff']))], data_files=[ ('share/sdaps/ui', glob.glob("sdaps/gui/*.ui") ), ('share/sdaps/tex', glob.glob('tex/*.cls') ), ('share/sdaps/tex', glob.glob('tex/*.tex') ), ('share/sdaps/tex', glob.glob('tex/*.sty') ), ], cmdclass = { "build" : sdaps_build, "build_tex" : sdaps_build_tex, "build_i18n" : sdaps_build_i18n, "build_help" : build_help.build_help, "build_icons" : build_icons.build_icons, "clean" : sdaps_clean_i18n } ) sdaps-1.9.8/test/0000755000175000000660000000000013611127124014354 5ustar benjaminlock00000000000000sdaps-1.9.8/test/data/0000755000175000000660000000000013611127124015265 5ustar benjaminlock00000000000000sdaps-1.9.8/test/data/info_files/0000755000175000000660000000000013611127124017402 5ustar benjaminlock00000000000000sdaps-1.9.8/test/data/info_files/test-tex-ids.2020-01-190000644000175000000660000000072713611126743022722 0ustar benjaminlock00000000000000[sdaps] title = Testfragebogen \LaTeX global_id = SDAPS [info] Author = Someone Umfrage = Testfragebogen [defs] # These values are not read back, they exist for information only! paper_width = 210.0 paper_height = 297.0 print_questionnaire_id = True print_survey_id = True style = code128 duplex = True checkmode = checkcorrect engine = pdflatex [questionnaire] # These values are not read back, they exist for information only! page_count = 2 survey_id = 3042674314 sdaps-1.9.8/test/data/info_files/test-tex-no-ids.2019-01-260000644000175000000660000000067613423054632023343 0ustar benjaminlock00000000000000[sdaps] title = asdf global_id = [info] Author = The Author Date = 10.03.2013 [defs] # These values are not read back, they exist for information only! paper_width = 210.0 paper_height = 297.0 print_questionnaire_id = False print_survey_id = True style = code128 duplex = True checkmode = checkcorrect engine = pdflatex [questionnaire] # These values are not read back, they exist for information only! page_count = 2 survey_id = 3297744764 sdaps-1.9.8/test/data/info_files/test-tex-no-ids.2019-11-230000644000175000000660000000067613566251651023351 0ustar benjaminlock00000000000000[sdaps] title = asdf global_id = [info] Author = The Author Date = 10.03.2013 [defs] # These values are not read back, they exist for information only! paper_width = 210.0 paper_height = 297.0 print_questionnaire_id = False print_survey_id = True style = code128 duplex = True checkmode = checkcorrect engine = pdflatex [questionnaire] # These values are not read back, they exist for information only! page_count = 2 survey_id = 1056296852 sdaps-1.9.8/test/data/tex/0000755000175000000660000000000013611127124016065 5ustar benjaminlock00000000000000sdaps-1.9.8/test/data/tex/code128_test_ids0000644000175000000660000000003613346275473021072 0ustar benjaminlock00000000000000Hello 12345 12 hello []()+-{} sdaps-1.9.8/test/data/tex/ids_test_export.csv0000644000175000000660000000156013421072233022022 0ustar benjaminlock00000000000000questionnaire_id,global_id,empty,valid,recognized,review,verified,1_review,1_1_review,1_1,1_2_review,1_2_1_review,1_2_1,1_2_2_review,1_2_2,1_2_3_review,1_2_3,1_2_4_review,1_2_4,2_review,2_1_review,2_1_1,2_1_2,2_1_3,2_1_4,2_1_5,2_1_6,2_1_7,2_1_8,2_1_9,2_2_review,2_2_1_review,2_2_1_1,2_2_1_2,2_2_1_3,2_2_2_review,2_2_2_1,2_2_2_2,2_2_2_3,2_2_3_review,2_2_3_1,2_2_3_2,2_2_3_3,3_review,3_1_review,3_1_1,3_2_review,3_2_1,3_3_review,3_3 Hello,SDAPS,0,1,1,global review comment,1,first header comment,,1,,,2,,3,q1 comment,4,,5,,q2 comment,1,1,1,1,1,1,1,1,1,,,1,1,1,,1,1,1,,1,1,1,,,1,,1,,2 12345,SDAPS,1,1,1,,0,,,-1,,,-1,,-1,,-1,,-1,,,0,0,0,0,0,0,0,0,0,,,0,0,0,,0,0,0,,0,0,0,,,0,,0,,-1 12hello,SDAPS,1,1,1,,0,,,-1,,,-1,,-1,,-1,,-1,,,0,0,0,0,0,0,0,0,0,,,0,0,0,,0,0,0,,0,0,0,,,0,,0,,-1 []()+-{},SDAPS,1,1,1,,0,,,-1,,,-1,,-1,,-1,,-1,,,0,0,0,0,0,0,0,0,0,,,0,0,0,,0,0,0,,0,0,0,,,0,,0,,-1 sdaps-1.9.8/test/data/tex/ids_test_import.csv0000644000175000000660000000062613421072233022015 0ustar benjaminlock00000000000000questionnaire_id,global_id,empty,valid,recognized,verified,1_1,1_2_1,1_2_2,1_2_3,1_2_4,2_1_1,2_1_2,2_1_3,2_1_4,2_1_5,2_1_6,2_1_7,2_1_8,2_1_9,2_2_1_1,2_2_1_2,2_2_1_3,2_2_2_1,2_2_2_2,2_2_2_3,2_2_3_1,2_2_3_2,2_2_3_3,3_1_1,3_2_1,3_3,review,1_review,1_2_3_review,2_1_review Hello,SDAPS,X,1,X,1,1,2,3,4,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,global review comment,first header comment,q1 comment,q2 comment sdaps-1.9.8/test/data/tex/questionnaire_with_ids.tex0000644000175000000660000000456613566251651023416 0ustar benjaminlock00000000000000\documentclass[pdf, print_questionnaire_id, sdaps_style=code128, globalid=SDAPS, english, stamp, pagemark]{sdapsclassic} \usepackage{ifxetex} \ifxetex \else \usepackage[utf8]{inputenc} \fi \usepackage{ulem} \usepackage{babel} \author{Someone} \title{Testfragebogen \LaTeX} \begin{document} % Will be printed on the report \begin{questionnaire} \addinfo{Umfrage}{Testfragebogen} \begin{info} Hier steht ein Informationstext, denn man ganz normal, \textbf{Fett}, \textit{kursiv}, oder \underline{unterstreichen} setzen kann.\par \centering Auch das Zentrieren des Textes ist möglich. \end{info} \section{Bewertungsfragen} \singlemark{Einzeln stehende Frage}{sehr gut}{sehr schlecht} \begin{markgroup}{Mehrere gebündelte Bewertungsfragen.} \markline{stolz}{sollte man haben}{finde ich unangenehm} \markline{hier ist ein langer text. Lorem ipsum dolor sit amet, consectetur adipiscing elit.}{finde ich gut}{finde ich voll doof} \markline{nett}{wichtig}{unwichtig} \markline{sympatisch}{wichtig}{unwichtig} \end{markgroup} \section{Fragen mit Auswahlfeldern} \begin{choicequestion}[cols=4]{Bitte wähle etwas aus oder schreibe in das Textfeld} \choiceitem{erste wahl} \choiceitem{zweite wahl} \choiceitem{dritte wahl} \choiceitem{vierte wahl} \choiceitem{fünfte wahl} \choiceitem{sechste wahl} \choicemulticolitem{2}{längere Auswahl mit langem Text damit mans merkt} \choiceitem{siebte wahl} \choiceitemtext{1cm}{2}{Sonstiges:} \end{choicequestion} Alternativ eine Liste von Auswahlfragen mit den gleichen Antworten. \begin{choicegroup}{Welche Software ist für die folgenden Anwendungen am besten geeignet?} \groupaddchoice{\LaTeX} \groupaddchoice{LibreOffice} \groupaddchoice{Microsoft Word} \choiceline{Texte schreiben} \choiceline{Mathematische Formeln} \choiceline{Fragebögen erstellen} \end{choicegroup} \section{Freitextfelder} Freitextfelder werden automatisch in der höhe Skaliert so dass die Seite voll wird. Es muss aber eine Mindesthöhe angegeben werden. \textbox{2cm}{Hier sollst du was eintragen} \textbox{4cm}{Und mal etwas mit macros \LaTeX} Und noch eine andere Frage. \singlemark{Wie gefällt dir dieser Bogen?}{sehr gut}{sehr schlecht} \end{questionnaire} \end{document} sdaps-1.9.8/test/data/tex/questionnaire_without_ids.tex0000644000175000000660000001342413566251651024137 0ustar benjaminlock00000000000000\documentclass[ % Babel language, also used to load translations english, % Use A4 paper size, you can change this to eg. letterpaper if you need % the letter format. The normal methods to modify the paper size should % be picked up by SDAPS automatically. % a4paper, % setting this might break the example scan unfortunately % letterpaper % % If you need it, you can add a custom barcode at the center %globalid=SDAPS, % % And the following adds a per sheet barcode at the bottom left %print_questionnaire_id, % % You can choose between twoside and oneside. twoside is the default, and % requires the document to be printed and scanned in duplex mode. %oneside, % % With SDAPS 1.1.6 and newer you can choose the mode used when recognizing % checkboxes. valid modes are "checkcorrect" (default), "check" and % "fill". %checkmode=checkcorrect, % % The following options make sense so that we can get a better feel for the % final look. sdaps_style=code128, pagemark, stamp]{sdapsclassic} \usepackage[utf8]{inputenc} % For demonstration purposes \usepackage{multicol} \author{The Author} \title{The Title} \begin{document} % Everything you do should be done inside the questionnaire environment. % If you don't like the default text at the beginning of each questionnaire % you can remove it with the optional [noinfo] parameter for the environment \begin{questionnaire} % There is a predefined "info" style to hilight some text. \begin{info} Some information here. Nothing special, just adds a line above/below. \end{info} % Use \addinfo to add metadata (which is printed on the report later on) \addinfo{Date}{10.03.2013} % You can structure the document using sections. You should not use % subsections yourself, as these are used to typeset question text. \section{Range Questions} % Lets ask some questions. % \singlemark creates a single range (1-5) question. \singlemark{How often do you use SDAPS?}{never}{daily} % Now we would like to ask multiple range questions that are similar. We % can use a markgroup environment to typeset many range questions under % one heading. \begin{markgroup}{What do you think about the following aspects of \LaTeX?} \markline{equation syntax}{bad}{good} \markline{rendered equations}{ugly}{beautiful} \markline{ease of use}{hard}{easy} \end{markgroup} \section{Choice Questions} We can also give users a question with predefined choices. Such a list of choices is typesetted using a tabularx environment with equally sized columns. Items can span multiple columns. \begin{choicequestion}[cols=3]{Which of the following Open Source Optical Mark Recognition software packages have you heard about?} \choiceitem{SDAPS} \choicemulticolitem{2}{Auto Multiple Choice} \choiceitem{QueXF} % Insert a text field. The freeform box automatically scales horizontally % The first parameter is the height of the box. The second parameter % is the amount of columns it should span. \choiceitemtext{1.2cm}{2}{Other:} \end{choicequestion} % And a more compact way of doing it; similar to markgroup \begin{choicegroup}{Which software do you prefere for the following tasks?} % We have to add the possible choices at the start. \groupaddchoice{\LaTeX} \groupaddchoice{LibreOffice} \groupaddchoice{Microsoft Word} \groupaddchoice{other} % After that it is possible to add each question. \choiceline{writing letters} \choiceline{creating tables} \choiceline{typesetting equations} \end{choicegroup} \section{Freeform text fields} SDAPS will extract freeform textfields such as below as images and put these into reports. SDAPS knows whether there is writing in the box and how large it is. % This is a textbox which is at least 2cm high. It will automatically scale % to fill the page. \textbox{2cm}{Do you have any comments?} % Force a new page here \newpage \section{Tricks and Features} SDAPS can also use circular checkboxes if you prefere. Or you can use the {\ttfamily multicol} package to create multi-column layouts as is done below. % Set checkbox style to be circular \def\checkboxstyle{ellipse} \begin{multicols}{2} \singlemark{This is a range question}{lower bound}{upper bound}% % Note that we need the % at the end of the last line to prevent % LaTeX from inserting too much whitespace. \label{somelabel} As you can see, this is a multi-column layout. The {\ttfamily markgroup} and {\ttfamily choicegroup} environments may be a bit tight in this mode. Lets put some more questions here, just because we can. \begin{choicequestion}[cols=1]{A choice question!} \choiceitem{first choice} \choiceitem{second choice} \choiceitem{third choice} \choiceitemtext{1.2cm}{1}{other:} \end{choicequestion} \singlemark{Another range question}{lower bound}{upper bound} This text is closer to the question compared to question~\ref{somelabel} because it is not starting a new paragraph. \textbox{3cm}{And a freeform text field} \end{multicols} That's it for the multi-column part; it was fun while it lasted! % Note that this document differes from the example by not including the % explanation about the dummy boxes for help strings. At this point this % is intentional as adding it back would break the currently stored IDs % for the test. \textbox*{2cm}{And textboxes with a fixed height. This one is exactly 2\,cm high.} % Reset checkbox style again. \def\checkboxstyle{box} \end{questionnaire} \end{document} sdaps-1.9.8/test/run-test-locally.sh0000755000175000000660000000005213346275473020146 0ustar benjaminlock00000000000000#!/bin/sh sh "run-test.sh" "../sdaps.py" sdaps-1.9.8/test/run-test.sh0000755000175000000660000000622613566250767016525 0ustar benjaminlock00000000000000#!/bin/sh # Stop if anything goes wrong set -e # Executable if [ "x$1" = "x" ]; then SDAPS="sdaps" else SDAPS="$1" fi # Set VERBOSE so that LaTeX compilation results end up on the console export VERBOSE=1 ########################################################### # Test Tex with IDs ########################################################### PROJECT="projects/test-tex-ids" # Create projects dir if it does not exist if [ ! -e `dirname $PROJECT` ]; then mkdir -p `dirname $PROJECT` fi # Remove project dir that may exist rm -rf "$PROJECT" "$SDAPS" setup "$PROJECT" "data/tex/questionnaire_with_ids.tex" # Create a cover page in projects/test/cover.pdf "$SDAPS" cover "$PROJECT" # Create sheets with some given IDs "$SDAPS" stamp "$PROJECT" -f "data/tex/code128_test_ids" "$SDAPS" ids "$PROJECT" -o "$PROJECT/ids" diff "data/tex/code128_test_ids" "$PROJECT/ids" # Add original PDF and convert "$SDAPS" add "$PROJECT" --convert "$PROJECT/stamped_1.pdf" # Recognize the empty pages (ie. the barcodes) "$SDAPS" recognize "$PROJECT" # Import some data "$SDAPS" csv import "$PROJECT" data/tex/ids_test_import.csv # Export data again "$SDAPS" csv export "$PROJECT" # And compare with expected result diff -qup data/tex/ids_test_export.csv "$PROJECT/data_1.csv" # Export all the other extra data "$SDAPS" csv export "$PROJECT" --images --question-images --quality # And finally, create a report with the fake result, both with tex and reportlab "$SDAPS" report "$PROJECT" "$SDAPS" report_tex "$PROJECT" ########################################################### # Test Tex without IDs ########################################################### PROJECT="projects/test-tex-no-ids" # Create projects dir if it does not exist if [ ! -e `dirname $PROJECT` ]; then mkdir -p `dirname $PROJECT` fi # Remove project dir that may exist rm -rf "$PROJECT" "$SDAPS" setup "$PROJECT" "data/tex/questionnaire_without_ids.tex" # Create a cover page in projects/test/cover.pdf "$SDAPS" cover "$PROJECT" # Run stamp, not neccessary "$SDAPS" stamp "$PROJECT" # Dump some infos "$SDAPS" info "$PROJECT" "$SDAPS" info "$PROJECT" title "$SDAPS" info "$PROJECT" title "asdf" # Add and recognize test data #"$SDAPS" add "$PROJECT" "data/tex/test_without_ids.tif" #"$SDAPS" recognize "$PROJECT" # And finally, create a report with the result #"$SDAPS" report_tex "$PROJECT" ########################################################### # Compare info files ########################################################### # Distributions: # Run with # IGNORE_PATTERN_EXTEND='\|^survey_id' # exported in the environment to prevent situations where texlive changes # cause build failures. for i in projects/*; do success=0 error=0 name=`basename "$i"` for j in "data/info_files/$name" data/info_files/$name.*; do if [ ! -f "$j" ]; then continue; fi; # This ignores the title; for whatever reason the \LaTeX # is written out differently with newer latex versions. diff -I '^title'"$IGNORE_PATTERN_EXTEND" "$j" "$i/info" && success=1 || error=1 done if [ $success -eq 0 -a $error -ne 0 ]; then # Throw error echo "None of the info files match for $name!" exit 1; fi done sdaps-1.9.8/tex/0000755000175000000660000000000013611127124014175 5ustar benjaminlock00000000000000sdaps-1.9.8/tex/class/0000755000175000000660000000000013611127124015302 5ustar benjaminlock00000000000000sdaps-1.9.8/tex/class/build.lua0000755000175000000660000000456113611121657017122 0ustar benjaminlock00000000000000#!/usr/bin/env texlua -- Build script for LaTeX3 "sdaps" files -- Identify the bundle and module: the module may be empty in the case where -- there is no subdivision bundle = "sdaps" module = "sdaps" modules = { "." } -- Location of main directory: use Unix-style path separators maindir = "." -- Non-standard settings cleanfiles = {"*.pdf", "*.tex", "*.zip"} packtdszip = true unpackdeps = { } uploadconfig = { author = "Benjamin Berg", email = "benjamin@sipsolutions.net", uploader = "Benjamin Berg", license = "lppl1.3c", summary = "SDAPS package for questionnaire creation", topic = {"class", "macro-supp", "package-devel", "exam", "pdf-forms", "table-long" }, ctanPath = "/macros/latex/contrib/sdaps", home = "https://sdaps.org", repository = "https://github.com/sdaps/sdaps-class/", bugtracker = "https://github.com/sdaps/sdaps-class/issues", update = true, version = "1.9.8", description = [[ This bundle contains LaTeX classes and packages to create machine readable questionnaires. Metadata is generated for the whole document and it is possible to process created forms fully automatically using the SDAPS main program. Features include: * PDF Form generation * Advanced array like layouting - Can flow over multiple pages and repeats the header automatically - Optional document wide alignment of array environments - Has complex layout features like rotating the headers to safe space - Ability to exchange rows and columns on the fly * Different question types: - Freeform text - Single/multiple choice questions - Range questions * Layouting questions in rows or columns * Possibility to pre-fill questinnaires from LaTeX Documentation can be found online at https://sdaps.org/class-doc ]] } -- Should we set any of the deps variables? -- typesetdeps = { } -- checkdeps = { } -- unpackdeps = { } checkruns = 3 -- No luatex support currently checkengines = { "pdftex", "xetex" } demofiles = { "arraydemo.tex", "testclassic.tex", "test.tex"} sourcefiles = { "README", "*.ins", "*.dtx", "sdapscode128.tex", "dict/*.dict" } installfiles = { "*.sty", "*.cls", "*.tex", "*.dict" } kpse.set_program_name ("kpsewhich") if not release_date then l3build = kpse.lookup ("l3build.lua") assert (l3build, "l3build is not installed!") dofile (kpse.lookup ("l3build.lua")) end sdaps-1.9.8/tex/class/examples/0000755000175000000660000000000013611127124017120 5ustar benjaminlock00000000000000sdaps-1.9.8/tex/class/examples/arraydemo.tex0000644000175000000660000002275613153476713021655 0ustar benjaminlock00000000000000\documentclass[ % Babel language, also used to load translations english, % Use A4 paper size, you can change this to eg. letterpaper if you need % the letter format. The normal methods to modify the paper size should % be picked up by SDAPS automatically. % a4paper, % setting this might break the example scan unfortunately % letterpaper % % If you need it, you can add a custom barcode at the center %globalid=SDAPS, % % And the following adds a per sheet barcode at the bottom left print_questionnaire_id, % % You can choose between twoside and oneside. twoside is the default, and % requires the document to be printed and scanned in duplex mode. oneside, % % With SDAPS 1.1.6 and newer you can choose the mode used when recognizing % checkboxes. valid modes are "checkcorrect" (default), "check" and % "fill". %checkmode=checkcorrect, % % The following options make sense so that we can get a better feel for the % final look. pagemark, stamp]{sdapsclassic} \usepackage{listings} \usepackage{multicol} \author{asdf} \title{blub} % Test support for repeating the environment. \ExplSyntaxOn %\seq_gset_from_clist:Nn \g__sdaps_questionnaire_ids_seq {a,b,c} \ExplSyntaxOff \showboxdepth=10 \showboxbreadth=10000 \tracingoutput=1 \tracingonline=1 \begin{document} \begin{questionnaire} \begin{verbatim} This is a test to check that verbatim works inside the questionnaire environment. @_öäü*'%asdf \end{verbatim} So, we can just demonstrate the sdapsarray environment quickly: \begin{sdapsarray} row head & col head & col head 2 \\ \vspace*{-\parskip}\vspace{-1em} \begin{lstlisting} This lstlistings is in the row header %&_\^ Note that verbatim would require more code right now. \end{lstlisting}\vspace{-1em} & cell 1 & cell 2 \\ row head3 & cell 3 & cell 4 \end{sdapsarray} Now something similar but flipping it and with rotated headers. The main difference is that instead of the verbatim we put a tabular environment into the header. \begin{sdapsarray}[flip,layouter=rotated,align=testalign] row head & col head & col head 2 \\ \sdapsnested{\begin{tabular}{cc} a & b \\ c & d \end{tabular}} & cell 1 & cell 2 \\ row head3 & cell 3 & cell 4 \end{sdapsarray} And a third test, we align this to the previous one! So if you have multiple choicearray questions you can make sure they all line up neatly (they will do so by default). \begin{sdapsarray}[align=testalign] & a & b \\ This is a lot of text to show that it will correctly wrap too. Note that we can use math $f(x) = y$ and \verb:\verb ?=!_\: for example & c & d \end{sdapsarray} The main disadvantages with this environment are: \begin{itemize} \item no row/column coloring support \item no support for grid lines \item no support for column or row spanning (unlikely to ever happen) \end{itemize} The big advantage is that you can easily create questions in a tabular fashion that contain fragile content and are stacked vertically instead of horizontally. Especially the second thing is hard to manage as it can be rather complicated to keep track of the metadata in that case. \section{Backward Compatbility} The following commands are implemented on top of the new commands and provide seemless backward compatbility to a lot of features of the old class. Some things are currently (and some may never) be implemented though. Also, the forms will not look identical. \textbox*{2cm}{asdf} \singlemark[var=testvar]{Hallo}{lower}{upper} \begin{choicequestion}[cols=3]{Which of the following OMR tools have you heard about?} \choiceitem{SDAPS} \choicemulticolitem{2}{ asdf } \choiceitem{QueXF} % Insert a text field. The freeform box automatically scales horizontally % The first parameter is the height of the box. The second parameter % is the amount of columns it should span. \choiceitemtext{1.2cm}{2}{Other \LaTeX:} \choicemulticolitem{2}{Auto Multiple Choice} \end{choicequestion} % And a more compact way of doing it; similar to markgroup \begin{choicegroup}{Which software do you prefere for the following tasks?} % We have to add the possible choices at the start. \groupaddchoice{\LaTeX} \groupaddchoice{LibreOffice} \groupaddchoice{Microsoft Word} \groupaddchoice{other} % After that it is possible to add each question. \choiceline{writing letters} \choiceline{creating tables} \choiceline{typesetting equations} \end{choicegroup} \textbox{2cm}{asdf} \section{New Commands} The choicegroup class is in reality pretty much the new choicearray environment which is renamed. This environment is based on the sdapsarray environment and gets all the features from this. You can now configure a lot of aspects: \begin{itemize} \item Optional argument of the environment: \begin{itemize} \item {\bfseries horizontal/vertical} flags for orientation \item {\bfseries layouter} any of the predefined sdapsarray layouters ("default" or "rotated" currently) \item {\bfseries align} to make different environments have equal column widths \item {\bfseries var} to append "\_param" to the generated variable names \item {\bfseries text} to specify a text for the metadata \end{itemize} \item Optional argument of the choice command: \begin{itemize} \item {\bfseries var} to append "\_param" to the generated variable name instead of numbering them \item {\bfseries text} to specify a text for the metadata and turn on the parser that support fragile content \end{itemize} \item Optional argument of the question command: \begin{itemize} \item {\bfseries var} to append "\_param" to the generated variable name instead of numbering them \item {\bfseries text} to specify a text for the metadata and turn on the parser that support fragile content \end{itemize} \end{itemize} So the same question as above, just with the {\bfseries vertical} option set and {\bfseries rotated} layouter. \begin{choicegroup}[vertical,layouter=rotated,var=testchoice]{Which software do you prefere for the following tasks?} % We have to add the possible choices at the start. \groupaddchoice[text=LaTeX,var=latex]{\LaTeX} \groupaddchoice[var=lo]{LibreOffice} \groupaddchoice[var=ms]{Microsoft Word} \groupaddchoice[var=other,text=other]{other, with a nice table: \begin{tabular}{cc} a & b \\ c & d\end{tabular}} % After that it is possible to add each question. \choiceline[var=letter]{writing letters} \choiceline[var=asdf,text=asdf]{ \begin{lstlisting} asdf \end{lstlisting}} \choiceline[var=eqn]{typesetting equations} \end{choicegroup} \newpage %\twocolumn \begin{multicols}{2} \begin{sdapsarray}[layouter=rotated,align=testalign] row head & col head & col head 2 \\ row 1 & cell 1 & cell 2 \\ row 2 & cell & cell \\ row 3 & cell & cell \\ row 4 & cell & cell \\ row 5 & cell & cell \\ row 6 & cell & cell \\ row 7 & cell & cell \\ row 8 & cell & cell \\ row 9 & cell & cell \\ row 10 & cell & cell \\ row 11 & cell & cell \\ row 12 & cell & cell \\ row 13 & cell & cell \\ row 14 & cell & cell \\ row 15 & cell & cell \\ row 16 & cell & cell \\ row 17 & cell & cell \\ row 18 & cell & cell \\ row 19 & cell & cell \\ row 20 & cell & cell \\ row 21 & cell & cell \\ row 22 & cell & cell \\ row 23 & cell & cell \\ row 24 & cell & cell \\ row 25 & cell & cell \\ row 26 & cell & cell \\ row 27 & cell & cell \\ row 28 & cell & cell \\ row 29 & cell & cell \\ row 30 & cell & cell \\ row 31 & cell & cell \\ row 32 & cell & cell \\ row 33 & cell & cell \\ row 34 & cell & cell \\ row 35 & cell & cell \\ row 36 & cell & cell \\ row 37 & cell & cell \\ row 38 & cell & cell \\ row 39 & cell & cell \\ row 40 & cell & cell \\ row 41 & cell & cell \\ row 42 & cell & cell \\ row 43 & cell & cell \\ row 44 & cell & cell \\ row 45 & cell & cell \\ row 46 & cell & cell \\ row 47 & cell & cell \\ row 48 & cell & cell \\ row 49 & cell & cell \\ row 50 & cell & cell \\ row 51 & cell & cell \\ row 52 & cell & cell \\ last (53) & cell & cell \end{sdapsarray} blub \end{multicols} \newpage \begin{rangearray}[var=testrange,other]{A test range question.} \range[var=a]{question}{lower}{upper}{other} \range[var=b,text=question sdaps,lower=lower sdaps,upper=upper sdaps]{question pdf}{lower pdf}{upper pdf}{} \range[var=c,other=other sdaps]{question}{lower3}{upper3}{other pdf} \end{rangearray} \begin{markgroup}{What do you think about the following aspects of \LaTeX?} \markline{equation syntax}{bad}{good} \markline{rendered equations}{ugly}{beautiful} \markline{ease of use}{hard}{easy} \end{markgroup} \begin{markgroup}{What do you think about the following aspects of \LaTeX?} \markline{equation syntax}{bad}{a} \markline{rendered equations}{ugly}{b} \markline{ease of use}{hard}{c} \end{markgroup} \end{questionnaire} \end{document} sdaps-1.9.8/tex/class/examples/autocross_countsheet.tex0000644000175000000660000000535213153476713024146 0ustar benjaminlock00000000000000\documentclass[english,a4,landscape]{sdapsclassic} \usepackage[utf8]{inputenc} \usepackage{multicol} %\author{FSG} \title{Cone sheet} \ExplSyntaxOn \newcommand{\countboxes}[2]{ \sdaps_qobject_begin:nnn { countboxes } { Choice } { #1 } \sdaps_context_append:nnn { var } { #1 } { _ } \vbox{ \vspace{1ex} \hbox{\int_step_inline:nnnn { 1 } { 1 } { #2 } { \sdaps_answer:n { 1_##1 } \sdaps_checkbox:nn {1_##1 } { } {} \int_compare:nT { ##1 < #2 } { ~ } } } \vspace{0.5ex} \hbox{ \int_step_inline:nnnn { 1 } { 1 } { #2 } { \sdaps_answer:n { 1_##1 } \sdaps_checkbox:nn {2_##1 } { } {} \int_compare:nT { ##1 < #2 } { ~ } } } \vspace*{0pt} } \sdaps_qobject_end:n { countboxes } } \newcommand{\mytextbox}[3]{ \sdaps_qobject_begin:nnn { mytextbox } { Text } { #3 } \dim_set:Nn \l_tmpa_dim { #1 } \dim_set:Nn \l_tmpb_dim { #1 } \dim_set:Nn \l_tmpa_dim { 0pt } \dim_set:Nn \l_tmpb_dim { \l_tmpb_dim } \sdaps_textbox_hstretch:nVVnn { #3 } \l_tmpa_dim \l_tmpb_dim { #2 } { 1 } \sdaps_qobject_end:n { mytextbox } } \newcommand{\inlinefilltextbox}[2]{ \sdaps_qobject_begin:nnn { inlinetextbox } { Text } { #2 } \dim_set:Nn \l_tmpa_dim { #1 } \dim_set:Nn \l_tmpb_dim { #1 } \dim_set:Nn \l_tmpa_dim { 0.5 \l_tmpa_dim - 0.8ex } \dim_set:Nn \l_tmpb_dim { 0.5 \l_tmpb_dim + 0.8ex } \sdaps_textbox_hstretch:nVVnn { #2 } \l_tmpa_dim \l_tmpb_dim { 1pt } { 1 } \sdaps_qobject_end:n { inlinetextbox } } \newcommand{\carline}[1]{ \sdaps_context_begin: \sdaps_context_append:nnn { var } { #1 } { _ } % The checkboxes are 3.5cm + 1pt \mytextbox{0.7cm + 2pt + 0.5ex}{2cm}{num} & %to be filled with the car numbers in advance or by hand (OCR?, identification by barcode?) \countboxes{1_cones}{ 10 } & \countboxes{1_oc}{ 2 } & \countboxes{1_ms}{ 2 } & \countboxes{2_cones}{ 10 } & \countboxes{2_oc}{ 2 } & \countboxes{2_ms}{ 2 } & \countboxes{2_onces}{ 10 } & \countboxes{2_oc}{ 2 } & \countboxes{2_ms}{ 2 } \sdaps_context_end: } \ExplSyntaxOff \begin{document} \begin{questionnaire} \begin{multicols}{2} Track Marshal Position: \inlinefilltextbox{1.2cm}{position} Track Marshal Names: \inlinefilltextbox{1.2cm}{names} \end{multicols} \begin{tabular}{c|ccc|ccc|ccc} Car No. & Run 1 Cones & OC & MS & Run 2 Cones & OC & MS & Re-Run Cones & OC & MS \\ \hline \carline{car_1} \\ \carline{car_2} \\ \carline{car_3} \\ \carline{car_4} \\ \carline{car_5} \\ \carline{car_6} \\ \carline{car_7} \\ \carline{car_8} \\ \carline{car_9} \\ \carline{car_10} \\ \carline{car_11} \end{tabular} \end{questionnaire} \end{document} sdaps-1.9.8/tex/class/examples/guadec.tex0000644000175000000660000001254213153476713021112 0ustar benjaminlock00000000000000\documentclass[ % Babel language, also used to load translations english, % Use A4 paper size, you can change this to eg. letterpaper if you need % the letter format. The normal methods to modify the paper size should % be picked up by SDAPS automatically. % a4paper, % setting this might break the example scan unfortunately % letterpaper % % If you need it, you can add a custom barcode at the center globalid=Flatpak, % % And the following adds a per sheet barcode at the bottom left %print_questionnaire_id, % % You can choose between twoside and oneside. twoside is the default, and % requires the document to be printed and scanned in duplex mode. %oneside, % % With SDAPS 1.1.6 and newer you can choose the mode used when recognizing % checkboxes. valid modes are "checkcorrect" (default), "check" and % "fill". %checkmode=checkcorrect, % % The following options make sense so that we can get a better feel for the % final look. pagemark, style=qr, stamp]{sdapsclassic} \author{} \title{GUADEC Workshop Evaluation} \begin{document} \begin{questionnaire} % \section{About you} % \begin{choicequestion}[cols=4]{Are you a foundation member?} % % Hack until this is properly supported somehow. % % Multiple answers are possible, but *shrug* % \ExplSyntaxOn % \sdaps_context_set:n {checkbox={ellipse}} % \ExplSyntaxOff % \choiceitem{Member} % \choiceitem{Not a member} % \choiceitem{Planning to be come one} % \end{choicequestion} % \begin{choicequestion}[cols=6]{What is our occupation?} % \ExplSyntaxOn % \sdaps_context_set:n {checkbox={ellipse}} % \ExplSyntaxOff % \choiceitem{Student} % \choicemulticolitem{2}{Software development} % \choiceitemtext{1.2cm}{3}{Other:} % \end{choicequestion} \section{General} \begin{markgroup}{Please rate the workshop overall} \markline{Was the workshop well prepared?}{very well}{not at all} \markline{Was the workshop well structured?}{very well}{not at all} \end{markgroup} \begin{markgroup}{Performance of the instructor} \markline{Was the instructor motivated?}{very motivated}{not motivated} \markline{How well did the instructor respond to questions?}{very well}{really bad} %\markline{Did the instructor keep eye contact?}{always}{never} \markline{Was the instructor easy to understand?}{always}{never} \markline{Was the instructor prepared?}{very well}{really bad} \end{markgroup} \begin{markgroup}{If applicable, please rate the hands on sessions} \markline{Were they well prepared?}{very well}{not at all} \markline{How detailed were the provided guides?}{too detailed}{too imprecise} \markline{Were the tutors able to help you if you got stuck?}{always}{never} \markline{Was the complexity appropriate for your experience?}{too complex}{too easy} \markline{Were the tasks at a reasonable pace for you?}{too quickly}{too slowly} \end{markgroup} \textbox*{4cm}{Please comment on the hands on sessions (e.g. good parts, bad parts, possible improvements)} \section{Materials} \begin{choicequestion}[cols=3]{What materials were used during the workshop?} \choiceitem{Slides} \choiceitem{Handouts} \choiceitem{Blackboard} \choiceitem{Online Documentation} \choiceitem{Prepared project files} \choiceitemtext{1.2cm}{1}{Other} \end{choicequestion} \begin{markgroup}{Please rate the slides (if applicable)} \markline{Were the slides detailed enough?}{absolutely}{not at all} \markline{Were the slides easy to understand?}{very easy}{not at all} \markline{Were the slides well structured?}{very well}{not at all} \markline{Were the slides well integrated into the workshop?}{very well}{not at all} \end{markgroup} \begin{markgroup}{Please rate other workshop material (if applicable)} \markline{Were the handouts detailed enough?}{absolutely}{not at all} \markline{Were the handouts easy to understand?}{very easy}{not at all} \markline{Were the handouts well structured?}{very well}{not at all} \markline{Were the handouts well integrated into the workshop?}{very well}{not at all} \end{markgroup} \textbox*{3cm}{Please comment on the material (e.g. good parts, bad parts, possible improvements)} \section{Overall impression} \singlemark{Did you enjoy this workshop}{very much}{not at all} \singlemark{Would you recommend this workshops to others?}{absolutely}{never} \singlemark{How do you rate the workshop organization (by the GUADEC team)?}{excellent}{poor} \textbox*{6cm}{Do you have any other comments?} \singlemark{Do you think that workshops at GUADEC are a good idea?}{absolutely}{not at all} % * Hands on % * Preparation of Tutors % * Required preparation for Workshop % * Struktur % * Beurteilung nach: % - Niveau % - Umfang % - Tempo % - ? % * Materialien (Folien/Blackboard/…) % - ausführlich genug % - verständlich % - strukturiert % - zur wiederholung geeignet % * Gesamtnote % * Dozent % - engagiert/motiviert % - beantwortet fragen % - theorie/praxis? % - blickkontakt % - vorbereitung? % - "wird wesentliches herausgearbeitet" % - Darbietung insgesamt \end{questionnaire} \end{document} sdaps-1.9.8/tex/class/sdapsarray.dtx0000644000175000000660000011770013606664075020221 0ustar benjaminlock00000000000000% \iffalse meta-comment % % Copyright (C) 2019 by Benjamin Berg % % This work may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3c % of this license or (at your option) any later version. % The latest version of this license is in % http://www.latex-project.org/lppl.txt % % This work has the LPPL maintenance status `maintained'. % % The Current Maintainer of this work is Benjamin Berg. % % \fi % % \iffalse %<*driver> \ProvidesFile{sdapsarray.dtx} % %\NeedsTeXFormat{LaTeX2e}[1999/12/01] %\ProvidesPackage{sdapsarray} %<*package> [2015/04/10 v0.1 Initial version of SDAPS array package] % % %<*driver> \documentclass{ltxdoc} \usepackage{sdapsarray}[2015/04/10] %\EnableCrossrefs \CodelineIndex \RecordChanges \begin{document} \DocInput{sdapsarray.dtx} \end{document} % % \fi % % \CheckSum{0} % % \CharacterTable % {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z % Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z % Digits \0\1\2\3\4\5\6\7\8\9 % Exclamation \! Double quote \" Hash (number) \# % Dollar \$ Percent \% Ampersand \& % Acute accent \' Left paren \( Right paren \) % Asterisk \* Plus \+ Comma \, % Minus \- Point \. Solidus \/ % Colon \: Semicolon \; Less than \< % Equals \= Greater than \> Question mark \? % Commercial at \@ Left bracket \[ Backslash \\ % Right bracket \] Circumflex \^ Underscore \_ % Grave accent \` Left brace \{ Vertical bar \| % Right brace \} Tilde \~} % % % \changes{v0.1}{2015/01/14}{Initial version} % % \GetFileInfo{sdapsarray.dtx} % % \DoNotIndex{\newcommand,\newenvironment} % % % \title{The \textsf{sdapsarray} package\thanks{This document % corresponds to \textsf{sdapsarray}~\fileversion, dated \filedate.}} % \author{Benjamin Berg \\ \texttt{benjamin@sipsolutions.net}} % % \maketitle % % \section{Documentation} % % Please refer to \url{https://sdaps.org/class-doc} for documentation. % % \StopEventually{\PrintChanges\PrintIndex} % % \section{Implementation} % % This package uses the \LaTeX3 language internally, so we need to enable it. % \begin{macrocode} % We need at least 2011-08-23 for \keys_set_known:nnN \RequirePackage{expl3}[2011/08/23] %\RequirePackage{xparse} \ExplSyntaxOn % \end{macrocode} % % And we need a number of other packages. % \begin{macrocode} \ExplSyntaxOff \RequirePackage{xparse} \RequirePackage{sdapsbase} \ExplSyntaxOn % \end{macrocode} % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % \subsection{Tempfile handling} % % This is a bit weird, but under some conditions we need extended information % about each row in the document (for page break detection). As it makes little % to no sense to load all this information into memory at start we use two % temporary files instead. As these files should not change their content % for reruns (that would break e.g. latexmk) we copy the "tic" file into "toc" % so that "toc" can be read while "tic" is being re-written. % We then go on to define a macro which will read a single % line and return true if it is different from the previous line. % This is the indicator that a page/column break has happened and the % row header needs to be inserted. % % \begin{macrocode} % This will change in early 2018, but the new code apparently does not % provide the old name of the definition. % i.e. this is a bad hack and should be removed latest in 2019 or so \cs_if_exist:NF \ior_str_get:NN { \cs_set_eq:Nc \ior_str_get:NN { ior_get_str:NN } } \bool_new:N \g__sdaps_array_info_open \bool_gset_false:N \g__sdaps_array_info_open \iow_new:N \g__sdaps_array_info_iow \ior_new:N \g__sdaps_array_info_ior \cs_generate_variant:Nn \int_set:Nn { Nf } \cs_generate_variant:Nn \coffin_join:NnnNnnnn { NnVNnVnn } \cs_new_protected_nopar:Nn \_sdaps_array_open_tmpfiles: { % Guard against being executed multiple times \bool_if:NF \g__sdaps_array_info_open { \bool_gset_true:N \g__sdaps_array_info_open % Also ensures toc file exists (i.e. is readable) \iow_open:Nn \g__sdaps_array_info_iow { \c_sys_jobname_str .sdapsarraytoc } \file_if_exist:nTF { \c_sys_jobname_str .sdapsarraytic } { % Copy into toc file, then open that. \ior_open:Nn \g__sdaps_array_info_ior { \c_sys_jobname_str .sdapsarraytic } \ior_str_map_inline:Nn \g__sdaps_array_info_ior { \iow_now:Nn \g__sdaps_array_info_iow { ##1 } } \ior_close:N \g__sdaps_array_info_ior \ior_open:Nn \g__sdaps_array_info_ior { \c_sys_jobname_str .sdapsarraytoc } } { } \iow_close:N \g__sdaps_array_info_iow \iow_open:Nn \g__sdaps_array_info_iow { \c_sys_jobname_str .sdapsarraytic } } } \tl_new:N \g__sdaps_array_last_row_tl \tl_gset_eq:NN \g__sdaps_array_last_row_tl \c_empty_tl \cs_new_protected_nopar:Nn \_sdaps_array_check_insert_header:N { \bool_gset_eq:NN #1 \c_false_bool \ior_if_eof:NF \g__sdaps_array_info_ior { \ior_str_get:NN \g__sdaps_array_info_ior \l_tmpa_tl \tl_if_eq:NNF \g__sdaps_array_last_row_tl \c_empty_tl { \tl_if_eq:NNF \g__sdaps_array_last_row_tl \l_tmpa_tl { \bool_gset_eq:NN #1 \c_true_bool } } \tl_gset_eq:NN \g__sdaps_array_last_row_tl \l_tmpa_tl } } % \end{macrocode} % % \subsection{Initialization} % % Global definitions and penalty constant. % % \begin{macrocode} \prop_new:N \g__sdaps_array_layouter_prop % XXX: Penalty in between rows. After the header a nobreak is inserted, but % do we want special penalties elsewhere (preventing orphans/widows?) \int_new:N \g_sdaps_array_row_penalty_tl \int_gset:Nn \g_sdaps_array_row_penalty_tl { 10 } % \end{macrocode} % % \subsection{Initialization} % % Define some routines to store width information for columns (across builds). % % \begin{macrocode} \tl_new:N \g_sdaps_array_shared_data_tl \tl_new:N \g_sdaps_array_stored_data_tl \tl_new:N \g_sdaps_array_local_data_tl \tl_new:N \g_sdaps_array_local_data_new_tl \prop_new:N \g__sdaps_array_stored_data_prop \prop_new:N \g__sdaps_array_shared_data_prop \prop_new:N \g__sdaps_array_local_data_prop \cs_generate_variant:Nn \prop_item:Nn { NV } \cs_new_protected_nopar:Nn \_sdaps_array_load_data: { \tl_gset:Nx \g_sdaps_array_stored_data_tl { \prop_item:NV \g__sdaps_array_stored_data_prop \l__sdaps_array_global_name_tl } \tl_gset:Nx \g_sdaps_array_shared_data_tl { \prop_item:NV \g__sdaps_array_shared_data_prop \l__sdaps_array_global_name_tl } \tl_gset:Nx \g_sdaps_array_local_data_tl { \prop_item:NV \g__sdaps_array_local_data_prop \l__sdaps_array_local_name_tl } } \cs_new_protected_nopar:Nn \_sdaps_array_store_data: { % Do not overwrite the "stored" data that we have right now. \prop_gput:NVV \g__sdaps_array_shared_data_prop \l__sdaps_array_global_name_tl \g_sdaps_array_shared_data_tl \immediate\write\@auxout{\exp_not:n{\sdapsarrayloadstoreddata}{\l__sdaps_array_global_name_tl}{\g_sdaps_array_shared_data_tl}} \tl_if_empty:NF \g_sdaps_array_local_data_new_tl { \immediate\write\@auxout{\exp_not:n{\sdapsarrayloadlocaldata}{\l__sdaps_array_local_name_tl}{\g_sdaps_array_local_data_new_tl}} } } % Define for loading sdaps code in aux file \cs_new_protected_nopar:Nn \sdaps_array_load_stored_data:nn { \prop_gput:Nnn \g__sdaps_array_stored_data_prop { #1 } { #2 } } \cs_new_eq:NN \sdapsarrayloadstoreddata \sdaps_array_load_stored_data:nn % Define for loading sdaps code in aux file \cs_new_protected_nopar:Nn \sdaps_array_load_local_data:nn { \prop_gput:Nnn \g__sdaps_array_local_data_prop { #1 } { #2 } } \cs_new_eq:NN \sdapsarrayloadlocaldata \sdaps_array_load_local_data:nn % \end{macrocode} % % \subsection{Array Layouter} % % \subsubsection{User facing macros} % % \begin{macrocode} \int_new:N \g__sdaps_array_current_id_int \tl_new:N \l__sdaps_array_global_name_tl \tl_new:N \l__sdaps_array_local_name_tl \cs_generate_variant:Nn \keys_set:nn { nf } \cs_new_protected_nopar:Nn \sdaps_array_begin:nn { \tl_set:Nx \l__sdaps_array_local_name_tl { sdapsarray \int_use:N\g__sdaps_array_current_id_int } \int_gincr:N \g__sdaps_array_current_id_int \tl_if_empty:nTF { #2 } { \tl_set:NV \l__sdaps_array_global_name_tl \l__sdaps_array_local_name_tl } { \tl_set:Nx \l__sdaps_array_global_name_tl { #2 } } \_sdaps_array_load_data: \keys_set:nf { sdaps / array } { \prop_item:Nn \g__sdaps_array_layouter_prop { #1 } } % Force cell layouter instead of column header layouter \bool_if:NT \l_sdaps_sdapsarray_no_header_bool { \tl_set:NV \l__sdaps_array_colhead_tl \l__sdaps_array_cell_tl } \_sdaps_array_open_tmpfiles: \tl_gset_eq:NN \g__sdaps_array_last_row_tl \c_empty_tl \bool_gset_true:N \g_sdaps_array_first_row_bool \l__sdaps_array_begin_tl } \cs_generate_variant:Nn \sdaps_array_begin:nn { Vn } \cs_generate_variant:Nn \sdaps_array_begin:nn { VV } \cs_generate_variant:Nn \sdaps_array_begin:nn { nV } \cs_new_protected_nopar:Nn \sdaps_array_begin:n { \sdaps_array_begin:nn { #1 } { } } \cs_new_protected_nopar:Nn \sdaps_array_row_start: { \l__sdaps_array_row_start_tl } \cs_new_protected_nopar:Nn \_sdaps_array_assign_use: { \box_use:N \l_tmpa_box \egroup } \cs_new_protected_nopar:Npn \sdaps_array_assign_colhead:Nw #1 { \l__sdaps_array_colhead_tl #1 } \cs_new_protected_nopar:Npn \sdaps_array_colhead:w { \bgroup \l__sdaps_array_colhead_tl \l_tmpa_box \bgroup \group_insert_after:N\_sdaps_array_assign_use: % swallow group opening token \tex_let:D\next= } \cs_new_protected:Npn \sdaps_array_assign_rowhead:Nw #1 { \l__sdaps_array_rowhead_tl #1 } \cs_new_protected:Npn \sdaps_array_rowhead:w { \bgroup \l__sdaps_array_rowhead_tl \l_tmpa_box \bgroup \group_insert_after:N\_sdaps_array_assign_use: % swallow group opening token \tex_let:D\next= } \cs_new_protected_nopar:Npn \sdaps_array_assign_cell:Nw #1 { \l__sdaps_array_cell_tl #1 } \cs_new_protected_nopar:Npn \sdaps_array_cell:w { \bgroup \l__sdaps_array_cell_tl \l_tmpa_box \bgroup \group_insert_after:N\_sdaps_array_assign_use: % swallow group opening token \tex_let:D\next= } % XXX: Could this live in local scope instead? \box_new:N \g__sdaps_array_header_box \dim_new:N \g__sdaps_array_header_dim \cs_new_protected_nopar:Nn \_sdaps_array_calc_interlineskip:nnN { \dim_compare:nNnTF { #1 } > { -1000pt } { \skip_set:Nn #3 { \baselineskip - #1 - #2 } \dim_compare:nNnF { #3 } > { \lineskiplimit } { \skip_set:Nn #3 { \lineskip } } } { \skip_set:Nn #3 { 0pt } } \skip_set:Nn #3 { #3 + \l_sdaps_sdapsarray_rowsep_dim } } \cs_new_protected_nopar:Nn \sdaps_array_row:NN { \if_mode_vertical: \else: \msg_error:nn { sdapsarray } { wrong_mode } \fi % XXX: \l_tmpa_dim is the height to the first baseline in the box. Note that % we use the real baseline in the case of the header row! \l__sdaps_array_row_tl #1 #2 \l_tmpb_box \l_tmpa_dim \bool_if:nTF { \g_sdaps_array_first_row_bool && !\l_sdaps_sdapsarray_no_header_bool } { % Stow away the box for later use \box_gset_eq:NN \g__sdaps_array_header_box \l_tmpb_box \dim_gset:Nn \g__sdaps_array_header_dim { \box_ht:N \g__sdaps_array_header_box + \box_dp:N \g__sdaps_array_header_box } } { % Pagebreak detection (not needed for header row) \_sdaps_array_check_insert_header:N \g_tmpa_bool \hbox_set:Nn \l_tmpb_box { \pdfsavepos \iow_shipout_x:Nn \g__sdaps_array_info_iow { \thepage, \the\pdflastxpos } \box_use:N \l_tmpb_box } } \bool_if:nTF { \g_sdaps_array_first_row_bool || \l_sdaps_sdapsarray_no_header_bool } { \_sdaps_array_calc_interlineskip:nnN { \prevdepth } { \l_tmpa_dim } \l_tmpa_skip \nointerlineskip \skip_vertical:n { \l_tmpa_skip } % However do not insert the rowskip in the case of the first line. % We rely on surrounding code to insert proper spacing before/after % the environment. \bool_if:NT \g_sdaps_array_first_row_bool { \skip_vertical:n { - \l_sdaps_sdapsarray_rowsep_dim } } \box_use:N \l_tmpb_box % For the header, insert a \nobreak, otherwise the normal inter-row penalty \bool_if:NTF \l_sdaps_sdapsarray_no_header_bool { \penalty\int_use:N\g_sdaps_array_row_penalty_tl } { \nobreak } \bool_gset_false:N \g_sdaps_array_first_row_bool } { % The idea is simple. Before every line the header is re-inserted (either % the real one or an empty box with the same dimensions). In the case that % there is *no* page break we insert a corresponding negative skip so that % the resulting skip (including interline skip) is exactly the normal % interline skip between the rows. % In the case that the skip *is* discarded we end up with the header box % and the normal interline skip between the new row and the header. i.e.: % skip = 1 * ( interlineskip_for_row - interlineskip_for_header - header_height - header_depth ) + header_height + header_depth + interlineksip_for_header % or % skip = 0 * ( interlineskip_for_row - interlineskip_for_header - header_height - header_depth ) + header_height + header_depth + interlineksip_for_header % Calculate interlineksip_for_row and interlineskip_for_header \_sdaps_array_calc_interlineskip:nnN { \prevdepth } { \l_tmpa_dim } \l_tmpa_skip \_sdaps_array_calc_interlineskip:nnN { \box_dp:N \g__sdaps_array_header_box } { \l_tmpa_dim } \l_tmpb_skip \nointerlineskip \skip_vertical:n { \l_tmpa_skip - \l_tmpb_skip } \kern -\g__sdaps_array_header_dim % Inser the real or fake box \bool_if:NTF \g_tmpa_bool { \box_use:N \g__sdaps_array_header_box } { \hrule height \box_ht:N \g__sdaps_array_header_box depth \box_dp:N \g__sdaps_array_header_box width 0pt } \nobreak % Insert the calculated interline skip (in the same way the TeX would do it. \nointerlineskip \skip_vertical:N \l_tmpb_skip \box_use:N \l_tmpb_box % And insert the sdapsarray sepecific inter row penalty. \penalty\int_use:N\g_sdaps_array_row_penalty_tl } } \cs_new_protected_nopar:Nn \sdaps_array_end: { \l__sdaps_array_end_tl \box_gclear:N \g__sdaps_array_header_box } % \end{macrocode} % % \subsubsection{Common Layouter Macros} % % \begin{macrocode} \tl_new:N \l__sdaps_array_begin_tl \tl_new:N \l__sdaps_array_row_start_tl \tl_new:N \l__sdaps_array_colhead_tl \tl_new:N \l__sdaps_array_rowhead_tl \tl_new:N \l__sdaps_array_cell_tl \tl_new:N \l__sdaps_array_row_tl \tl_new:N \l__sdaps_array_end_tl \keys_define:nn { sdaps / array } { begin .tl_set:N = \l__sdaps_array_begin_tl, row_start .tl_set:N = \l__sdaps_array_row_start_tl, colhead .tl_set:N = \l__sdaps_array_colhead_tl, rowhead .tl_set:N = \l__sdaps_array_rowhead_tl, cell .tl_set:N = \l__sdaps_array_cell_tl, row .tl_set:N = \l__sdaps_array_row_tl, end .tl_set:N = \l__sdaps_array_end_tl, } \seq_new:N \g_sdaps_array_overhangs_left_seq \seq_new:N \g_sdaps_array_overhangs_right_seq \seq_new:N \g_sdaps_array_shared_colwidths_seq \seq_new:N \g_sdaps_array_stored_colwidths_seq \cs_new_protected_nopar:Npn \_sdaps_array_rowhead_default:Nw #1 { \tl_if_empty:NTF \g_sdaps_array_local_data_tl { \tl_if_empty:NTF \g_sdaps_array_local_data_new_tl { \dim_set:Nn \l_tmpa_dim { 0.5 \hsize } } { \dim_set:Nn \l_tmpa_dim { \g_sdaps_array_local_data_new_tl } } } { \dim_set:Nn \l_tmpa_dim { \g_sdaps_array_local_data_tl } } % \vbox_set_top:Nw is still missing as of 2017-08-11 \tex_setbox:D #1 \tex_vtop:D \bgroup \sdaps_if_rtl:TF { \raggedright } { \raggedleft } \hsize=\dim_use:N\l_tmpa_dim \group_begin:\bgroup \group_insert_after:N \group_end: \group_insert_after:N \egroup % swallow group opening token \tex_let:D\next= } \cs_new_protected_nopar:Npn \_sdaps_array_cell_default:Nw #1 { \hbox_set:Nw #1 \bgroup % swallow group opening token \group_insert_after:N \hbox_set_end: \tex_let:D\next= } \cs_new:Nn \_sdaps_array_cell_rotated_end: { \hbox_set_end: \dim_set:Nn \l_tmpa_dim { \box_ht:N \l_tmpa_box } \dim_set:Nn \l_tmpb_dim { \box_dp:N \l_tmpa_box } \dim_set:Nn \l_tmpa_dim { \l_sdaps_sdapsarray_angle_sine_tl \l_tmpa_dim } \dim_set:Nn \l_tmpb_dim { \l_sdaps_sdapsarray_angle_sine_tl \l_tmpb_dim } \box_rotate:Nn \l_tmpa_box { \l_sdaps_sdapsarray_angle_int } % We want the baseline of the box to be centered, that only works if we % leave the same space both ways. % That is not ideal, but we cannot move the cell content accordingly. \dim_set:Nn \l_tmpb_dim { \dim_max:nn { \l_tmpa_dim } { \l_tmpb_dim } } \skip_horizontal:n { \l_tmpb_dim } \rlap{ \skip_horizontal:n { -\l_tmpa_dim } \box_use:N \l_tmpa_box } \skip_horizontal:n { \l_tmpb_dim } % dummy skip that will be removed again by other code \skip_horizontal:n { 0pt } \dim_set:Nn \l_tmpa_dim { \l_tmpa_dim + \l_tmpb_dim } \dim_set:Nn \l_tmpb_dim { \box_wd:N \l_tmpa_box } \dim_set:Nn \l_tmpa_dim { \dim_max:nn { 0pt } { \l_tmpb_dim - \l_tmpa_dim } } \seq_gpush:Nn \g_sdaps_array_overhangs_left_seq { 0pt } \seq_gpush:Nx \g_sdaps_array_overhangs_right_seq { \dim_use:N \l_tmpa_dim } \egroup \hbox_set_end: } % Only sane for header row \cs_new_protected_nopar:Npn \_sdaps_array_cell_rotated:Nw #1 { \hbox_set:Nw #1 \bgroup \hbox_set:Nw \l_tmpa_box \bgroup \group_insert_after:N \_sdaps_array_cell_rotated_end: % swallow group opening token \tex_let:D\next= } % XXX: A parbox layouter with fixed width would be nice %\cs_new_protected_nopar:Nn \sdaps_array_cell_fixed:n {} \cs_new_protected_nopar:Nn \_sdaps_array_begin_default: { \tl_if_empty:NTF \g_sdaps_array_shared_data_tl { \seq_clear:N \g_sdaps_array_shared_colwidths_seq } { \seq_gset_split:NnV \g_sdaps_array_shared_colwidths_seq { ~ } \g_sdaps_array_shared_data_tl } \tl_if_empty:NTF \g_sdaps_array_stored_data_tl { \seq_clear:N \g_sdaps_array_stored_colwidths_seq } { \seq_gset_split:NnV \g_sdaps_array_stored_colwidths_seq { ~ } \g_sdaps_array_stored_data_tl } } \cs_new_protected_nopar:Nn \_sdaps_array_end_default: { \tl_gset:Nx \g_sdaps_array_shared_data_tl { \seq_use:Nn \g_sdaps_array_shared_colwidths_seq { ~ } } \tl_gset:Nx \g_sdaps_array_stored_data_tl { \seq_use:Nn \g_sdaps_array_stored_colwidths_seq { ~ } } % Clear the global sequences, to save memory \seq_gclear:N \g_sdaps_array_overhangs_left_seq \seq_gclear:N \g_sdaps_array_overhangs_right_seq \seq_gclear:N \g_sdaps_array_shared_colwidths_seq \seq_gclear:N \g_sdaps_array_stored_colwidths_seq \_sdaps_array_store_data: } \cs_new_protected_nopar:Nn \_sdaps_array_row_start_default: { \seq_gclear:N \g_sdaps_array_overhangs_left_seq \seq_gclear:N \g_sdaps_array_overhangs_right_seq } \cs_new_protected_nopar:Nn \_sdaps_array_row:NNNN { % #1: A vbox with baseline on the *first* item containing the row header % (\vtop in plain TeX). % #2: Data cells packed into an hbox. Each of these needs to be set to the % correct width and inserted. % #3: The box register to store the resulting hbox in. The depth of this box % needs to be correct to calculate the interline glue to the following % row. % #4: A dim register to store the height of the box in for the purpose of % calculating the interline glue in front of the produced row. % % { \dim_use:N\@totalleftmargin } { \dim_use:N\linewidth } % The macro should create an hbox which is exactly \linewidth wide and also % contains internal indentation by \@totalleftmargin into the box register #3. % The box will be used while in vertical mode and may% be inserted multiple % times in the case of the header row. % To simplify the iteration it is guaranteed that the data cell boxes are not % completely empty. This means the code can simply unbox until it sees a box % that is void. \seq_gclear:N \g_tmpa_seq % Insert the boxes into a local hbox to work with them \hbox_set:Nn #2 { \hbox_unpack:N #2 % Handle the overhang, note that we modify the \g_sdaps_array_overhangs_right_seq locally only! \seq_pop:NNTF \g_sdaps_array_overhangs_right_seq \l_tmpa_tl { \dim_set:Nn \l_tmpb_dim { \l_tmpa_tl } } { \dim_set:Nn \l_tmpb_dim { 0pt } } % Implicit "last" column that contains the overhang \seq_gpop:NNTF \g_sdaps_array_shared_colwidths_seq \l_tmpa_tl { \dim_set:Nn \l_tmpa_dim { \l_tmpa_tl } } { \dim_set:Nn \l_tmpa_dim { 0pt } } \dim_set:Nn \l_tmpa_dim { \dim_max:nn { \l_tmpa_dim } { \l_tmpb_dim } } % MAX with stored values (NOTE: sequence only modified in local scope) \seq_pop:NNTF \g_sdaps_array_stored_colwidths_seq \l_tmpa_tl { \dim_set:Nn \l_tmpb_dim { \l_tmpa_tl } } { \dim_set:Nn \l_tmpb_dim { 0pt } } % Store value from this run, and then calculate max with previous run \seq_gput_right:Nx \g_tmpa_seq { \dim_use:N \l_tmpa_dim } \dim_set:Nn \l_tmpa_dim { \dim_max:nn { \l_tmpa_dim } { \l_tmpb_dim } } % Insert the overhang space \hbox_set:Nn \l_tmpa_box { \skip_horizontal:n { \l_tmpa_dim } } % Now grab the first of the cells, and then loop over the rest \box_set_to_last:N #2 \bool_do_while:nn { ! \box_if_empty_p:N #2 } { % Strip any trailing glue (i.e. space) coming from the user (for the % leading side we ensure that \tex_ignorespaces:D is called). % Note that this may remove e.g. a trailing \hfill from the user, the % user needs to work around that (in the same way as is required in e.g. % tabular). \hbox_set:Nn #2 { \hbox_unpack:N #2 \unskip } % Pop the target width for the current box (i.e. we don't globally % modify the clist here). \seq_gpop:NNTF \g_sdaps_array_shared_colwidths_seq \l_tmpa_tl { \dim_set:Nn \l_tmpa_dim { \l_tmpa_tl } } { \dim_set:Nn \l_tmpa_dim { 0pt } } % Calculate the maximum width of current and previous items \dim_set:Nn \l_tmpa_dim { \dim_max:nn { \box_wd:N #2 } { \l_tmpa_dim } } % MAX with stored values (NOTE: sequence only modified in local scope) \seq_pop:NNTF \g_sdaps_array_stored_colwidths_seq \l_tmpa_tl { \dim_set:Nn \l_tmpb_dim { \l_tmpa_tl } } { \dim_set:Nn \l_tmpb_dim { 0pt } } % Store value from this run, and then calculate max with previous run \seq_gput_right:Nx \g_tmpa_seq { \dim_use:N \l_tmpa_dim } \dim_set:Nn \l_tmpa_dim { \dim_max:nn { \l_tmpa_dim } { \l_tmpb_dim } } % Set the box into a new box with the correct width which contains fil % to center it. \hbox_set_to_wd:Nnn \l_tmpb_box \l_tmpa_dim { \hfil \hbox_unpack:N #2 \hfil } % This loops works backward, so attach the cell on the right side. % We used to make sure that it is layed out in order, but that is now % obsolete and doing it out of order is simpler in RTL mode. \sdaps_if_rtl:TF { % The boxes are shown on the page from LTR \hbox_set:Nn \l_tmpa_box { \box_use:N \l_tmpa_box \skip_horizontal:n { \l_sdaps_sdapsarray_colsep_dim } \box_use:N \l_tmpb_box \skip_horizontal:n { \l_sdaps_sdapsarray_colsep_dim } } } { \hbox_set:Nn \l_tmpa_box { \skip_horizontal:n { \l_sdaps_sdapsarray_colsep_dim } \box_use:N \l_tmpb_box \skip_horizontal:n { \l_sdaps_sdapsarray_colsep_dim } \box_use:N \l_tmpa_box } } % Grab next cell \box_set_to_last:N #2 } % Get the coffin out of the nested scope by placing it into the box and % placing that into it again ... \box_use:N \l_tmpa_box } \hcoffin_set:Nn \l_tmpa_coffin { \box_use_drop:N #2 } \seq_gconcat:NNN \g_sdaps_array_shared_colwidths_seq \g_tmpa_seq \g_sdaps_array_shared_colwidths_seq \seq_gclear:N \g_tmpa_seq % Calculate the space that is left for the header column \dim_set:Nn \l_tmpa_dim { \linewidth - \coffin_wd:N \l_tmpa_coffin - 2\l_sdaps_sdapsarray_colsep_dim } \tl_gset:Nx \g_sdaps_array_local_data_new_tl { \dim_use:N \l_tmpa_dim } % TODO: The \hfil here is a hack to prevent a warning if the vbox is empty. % Unfortunately checking for an empty box does not work for some reason. \dim_set:Nn \l_tmpb_dim { \box_ht:N #1 } \sdaps_if_rtl:TF { \hcoffin_set:Nn \l_tmpb_coffin { \hbox_to_wd:nn \l_tmpa_dim { \hfil \vbox:n { \vbox_unpack_clear:N #1 } } \skip_horizontal:n { \l_sdaps_sdapsarray_colsep_dim } } \tl_set:Nn \l_tmpa_tl { l } \tl_set:Nn \l_tmpb_tl { r } } { \hcoffin_set:Nn \l_tmpb_coffin { \skip_horizontal:n { \l_sdaps_sdapsarray_colsep_dim } \hbox_to_wd:nn \l_tmpa_dim { \hfil \vbox:n { \vbox_unpack_clear:N #1 } } } \tl_set:Nn \l_tmpa_tl { r } \tl_set:Nn \l_tmpb_tl { l } } \dim_set:Nn \l_tmpa_dim { \coffin_ht:N \l_tmpb_coffin } % If the first/last baseline differ then center the vbox, otherwise align the % baseline with the cells \dim_compare:nNnTF { \l_tmpa_dim } = { \l_tmpb_dim } { \coffin_join:NnVNnVnn \l_tmpb_coffin { H } \l_tmpa_tl \l_tmpa_coffin { H } \l_tmpb_tl { \l_sdaps_sdapsarray_colsep_dim } { 0pt } \dim_set:Nn #4 { \coffin_ht:N \l_tmpb_coffin } } { \coffin_join:NnVNnVnn \l_tmpb_coffin { vc } \l_tmpa_tl \l_tmpa_coffin { vc } \l_tmpb_tl { \l_sdaps_sdapsarray_colsep_dim } { 0pt } % XXX: Assume that the header is higher than the content cells \dim_set:Nn #4 { \l_tmpb_dim } } \hbox_set:Nn #3 { \skip_horizontal:N \@totalleftmargin \coffin_typeset:Nnnnn \l_tmpb_coffin { H } { l } { 0pt } { 0pt } } } \prop_gput:Nnn \g__sdaps_array_layouter_prop { default } { begin = { \_sdaps_array_begin_default: }, row_start = { \_sdaps_array_row_start_default: }, rowhead = { \_sdaps_array_rowhead_default:Nw }, colhead = { \_sdaps_array_cell_default:Nw }, cell = { \_sdaps_array_cell_default:Nw }, row = { \_sdaps_array_row:NNNN }, end = { \_sdaps_array_end_default: }, } \prop_gput:Nnn \g__sdaps_array_layouter_prop { rotated } { begin = { \_sdaps_array_begin_default: }, row_start = { \_sdaps_array_row_start_default: }, rowhead = { \_sdaps_array_rowhead_default:Nw }, colhead = { \_sdaps_array_cell_rotated:Nw }, cell = { \_sdaps_array_cell_default:Nw }, row = { \_sdaps_array_row:NNNN }, end = { \_sdaps_array_end_default: }, } % \end{macrocode} % % \subsection{Exporting a tabular/array like environment} % % \subsubsection{Helper required for the environment} % % \begin{macrocode} \bool_new:N \g_sdaps_array_first_row_bool \bool_new:N \l__sdaps_sdapsarray_in_top_group_bool \bool_new:N \l__sdaps_sdapsarray_have_content_bool \bool_new:N \l_sdaps_sdapsarray_flip_bool \tl_new:N \l_sdaps_sdapsarray_layouter_tl \tl_new:N \l_sdaps_sdapsarray_align_tl \bool_new:N \l_sdaps_sdapsarray_keepenv_bool \int_new:N \l_sdaps_sdapsarray_angle_int \tl_new:N \l_sdaps_sdapsarray_angle_sine_tl \dim_new:N \l_sdaps_sdapsarray_colsep_dim \dim_new:N \l_sdaps_sdapsarray_rowsep_dim \bool_new:N \l_sdaps_sdapsarray_no_header_bool \keys_define:nn { sdaps / sdapsarray } { flip .bool_set:N = \l_sdaps_sdapsarray_flip_bool, flip .initial:n = false, flip .default:n = true, layouter .tl_set:N = \l_sdaps_sdapsarray_layouter_tl, layouter .initial:n = default, align .tl_set:N = \l_sdaps_sdapsarray_align_tl, align .initial:n = { }, keepenv .bool_set:N = \l_sdaps_sdapsarray_keepenv_bool, keepenv .initial:n = false, keepenv .default:n = true, no_header .bool_set:N = \l_sdaps_sdapsarray_no_header_bool, no_header .initial:n = false, no_header .default:n = true, angle .code:n = { \int_set:Nn \l_sdaps_sdapsarray_angle_int {#1} \tl_set:Nx \l_sdaps_sdapsarray_angle_sine_tl { \fp_to_decimal:n {sind(#1)}} }, angle .initial:n = 70, colsep .dim_set:N = \l_sdaps_sdapsarray_colsep_dim, colsep .initial:n = 6pt, rowsep .dim_set:N = \l_sdaps_sdapsarray_rowsep_dim, rowsep .initial:n = 0pt, } % \end{macrocode} % % \subsubsection{Environment definition} % % \begin{macrocode} \cs_new_nopar:Nn \l_sdaps_sdapsarray_alignment_set_have_content: { \bool_set_true:N\l__sdaps_sdapsarray_have_content_bool } \cs_new_nopar:Nn \_sdaps_sdapsarray_alignment: { % End the last group, which will be the group that was begun earlier. % If the earlier cell was the first one, then this egroup also starts the % hbox to temporarily store the cells. \egroup \bool_if:NF \l__sdaps_sdapsarray_in_top_group_bool { \msg_error:nnn { sdapsarray } { unmatched_grouping_level } { an~alignment~tab } } % We need to notify the outside scope that there are items, will be inserted % multiple times, but that does not matter. \group_insert_after:N\l_sdaps_sdapsarray_alignment_set_have_content: % Just in case someone leaked a change into our scope \bool_if:NF \l_sdaps_sdapsarray_keepenv_bool { \cs_set_eq:NN \cr \_sdaps_sdapsarray_newline: \cs_set_eq:NN \\ \cr } % Define a cell now, we can just put everything into a new cell, and that % should work fine. % Note that cells are not safe for fragile commands at the moment. \_sdaps_sdapsarray_cell:w \bgroup \bool_set_false:N \l__sdaps_sdapsarray_in_top_group_bool \cs_set_eq:NN \\ \cr \tex_ignorespaces:D } \msg_new:nnn { sdapsarray } { unmatched_grouping_level } { The~grouping~level~of~a~cell~was~not~even.~Please~ensure~all~braces~are~balanced~out!~This~error~occured~at~#1. } \msg_new:nnn { sdapsarray } { unequal_cols } { The~number~of~columns~is~not~equal~for~all~rows. } \msg_new:nnn { sdapsarray } { no_new_line_at_end } { You~have~terminated~the~last~line~with~\textbackslash\textbackslash~or~similar.~This~can~have~side~effects,~please~remove~it. } \msg_new:nnn { sdapsarray } { wrong_mode } { The~sdapsarray~environment~can~only~function~in~vertical~mode~(both~inner~and~outer). } \cs_new:Nn \_sdaps_sdapsarray_start_cells: { \bool_if:NF \l__sdaps_sdapsarray_in_top_group_bool { \msg_error:nnn { sdapsarray } { unmatched_grouping_level } { the~end~of~a~row~header } } \egroup % We are in the environment scope again here % Notify code that we are going to generate cells for a new row. \sdaps_array_row_start: % Start an hbox to stow away the cells. % The rest of the setup happens in the alignment handler \hbox_set:Nw \l_tmpb_box \bgroup \group_insert_after:N \hbox_set_end: \bool_set_true:N \l__sdaps_sdapsarray_in_top_group_bool } \cs_new_nopar:Nn \_sdaps_sdapsarray_linestart: { \sdaps_array_assign_rowhead:Nw \l_tmpa_box \bgroup \cs_set_eq:NN \\ \cr \bool_set_true:N \l__sdaps_sdapsarray_in_top_group_bool \bgroup \group_insert_after:N \_sdaps_sdapsarray_start_cells: \bool_set_false:N \l__sdaps_sdapsarray_in_top_group_bool % Ignore following spaces by the user \tex_ignorespaces:D } \cs_new_nopar:Nn \_sdaps_sdapsarray_newline: { \egroup \bool_if:NF \l__sdaps_sdapsarray_in_top_group_bool { \msg_error:nnn { sdapsarray } { unmatched_grouping_level } { the~end~of~a~row } } \egroup % We are in the environment scope again here % Output the last line if the cells were non-empty. \bool_if:NT \l__sdaps_sdapsarray_have_content_bool { \sdaps_array_row:NN \l_tmpa_box \l_tmpb_box } \bool_set_false:N \l__sdaps_sdapsarray_have_content_bool \cs_set_eq:NN \_sdaps_sdapsarray_cell:w \sdaps_array_cell:w \_sdaps_sdapsarray_linestart: } \cs_new:Npn\sdaps_array_nested_alignenv: { \char_set_catcode_alignment:N & \cs_set_eq:NN \cr \sdaps_orig_cr \cs_set_eq:NN \\ \sdaps_orig_backslash } \cs_new:Npn\sdaps_array_nested_alignenv:w { \bgroup \sdaps_array_nested_alignenv: % swallow group opening token \tex_let:D\next= } \cs_new_eq:NN \sdapsnested \sdaps_array_nested_alignenv:w \group_begin: \char_set_catcode_active:N & \cs_new:Nn \_sdaps_sdapsarray_defines: { \cs_set_eq:NN \sdaps_orig_cr \cr \cs_set_eq:NN \sdaps_orig_backslash \\ \bool_if:NF \l_sdaps_sdapsarray_keepenv_bool { \char_set_catcode_active:N & \cs_set_eq:NN \cr \sdaps_array_newline: \cs_set_eq:NN \\ \cr \cs_set_eq:NN & \sdaps_array_alignment: } } \group_end: %%%%%% % Flipping environment %%%%%% % First some helpers \box_new:N \l_sdaps_sdapsarray_headers_box \box_new:N \l_sdaps_sdapsarray_boxlist_head_box \box_new:N \l_sdaps_sdapsarray_boxlist_tail_box \cs_new_protected:Nn \_sdaps_sdapsarray_prepend_box:NN { \hbox_set:Nn #2 { \box_use:N #1 \hbox_unpack:N #2 } \box_clear:N #1 } \cs_new_protected:Nn \_sdaps_sdapsarray_append_box:NN { \hbox_set:Nn #2 { \hbox_unpack:N #2 \box_use:N #1 } \box_clear:N #1 } \cs_new_protected:Nn \_sdaps_sdapsarray_pop_last_box:NN { \hbox_set:Nn #2 { \hbox_unpack:N #2 \box_gset_to_last:N \g_tmpa_box } \box_set_eq:NN #1 \g_tmpa_box \box_gclear:N \g_tmpa_box } \cs_new_protected:Nn \_sdaps_sdapsarray_pop_last_hbox_unpack:NN { \_sdaps_sdapsarray_pop_last_box:NN #1 #2 \hbox_set:Nn #1 { \hbox_unpack:N #1 \box_gset_to_last:N \g_tmpa_box } \box_set_eq:NN #1 \g_tmpa_box \box_gclear:N \g_tmpa_box } \cs_new_protected:Nn \_sdaps_sdapsarray_boxlist_void_if_empty:N { \hbox_set:Nn #1 { \hbox_unpack:N #1 \box_set_to_last:N #1 \box_if_empty:NTF #1 { \bool_gset_true:N \g_tmpa_bool } { \box_use:N #1 \bool_gset_false:N \g_tmpa_bool } } \bool_if:NT \g_tmpa_bool { \box_clear:N #1 } } % Lets say we are in row 4, cell 2 as defined in the environment, so the actual % position is 2, 4. Minus the row headers, this gives us 2, 3. % This means we need to append the cell to the box 3rd last box. % In that case we have to append the cell \cs_new_protected_nopar:Nn \_sdaps_sdapsarray_alignment_flip: { \_sdaps_sdapsarray_end_cell_flip: % Just in case someone leaked a change into our scope \bool_if:NF \l_sdaps_sdapsarray_keepenv_bool { \cs_set_eq:NN \cr \_sdaps_sdapsarray_newline_flip: \cs_set_eq:NN \\ \cr } % Next up is either a cell or a row header. We can figure that out by checking % that the row headings box is void \box_if_empty:NTF \l_sdaps_sdapsarray_headers_box { \sdaps_array_assign_rowhead:Nw \l_tmpa_box \bgroup \bool_set_false:N \l__sdaps_sdapsarray_in_top_group_bool \cs_set_eq:NN \\ \cr % Ignore following spaces by the user \tex_ignorespaces:D } { \sdaps_array_assign_cell:Nw \l_tmpa_box \bgroup \bool_set_false:N \l__sdaps_sdapsarray_in_top_group_bool \cs_set_eq:NN \\ \cr \tex_ignorespaces:D } } \cs_new_nopar:Nn \_sdaps_sdapsarray_end_cell_flip: { \egroup % Finish of the cell \bool_if:NF \l__sdaps_sdapsarray_in_top_group_bool { \msg_error:nnn { sdapsarray } { unmatched_grouping_level } { end~of~cell~or~row } } % Get last box from head \_sdaps_sdapsarray_pop_last_box:NN \l_tmpb_box \l_sdaps_sdapsarray_boxlist_head_box % Append the new box to the list of boxes for this row \_sdaps_sdapsarray_append_box:NN \l_tmpa_box \l_tmpb_box % Prepend the new box to the tail \_sdaps_sdapsarray_prepend_box:NN \l_tmpb_box \l_sdaps_sdapsarray_boxlist_tail_box } \cs_new_nopar:Nn \_sdaps_sdapsarray_end_line_flip: { % At the end of the line, move tail into head. % First check that head is empty. \_sdaps_sdapsarray_boxlist_void_if_empty:N \l_sdaps_sdapsarray_boxlist_head_box \box_if_empty:NF \l_sdaps_sdapsarray_boxlist_head_box { \msg_error:nn { sdapsarray } { unequal_cols } } \box_set_eq:NN \l_sdaps_sdapsarray_boxlist_head_box \l_sdaps_sdapsarray_boxlist_tail_box \box_clear:N \l_sdaps_sdapsarray_boxlist_tail_box % If this was the first row, store it away, these are the headings. \box_if_empty:NT \l_sdaps_sdapsarray_headers_box { \box_set_eq:NN \l_sdaps_sdapsarray_headers_box \l_sdaps_sdapsarray_boxlist_head_box \box_clear:N \l_sdaps_sdapsarray_boxlist_head_box } } \cs_new_nopar:Nn \_sdaps_sdapsarray_newline_flip: { \_sdaps_sdapsarray_end_cell_flip: \_sdaps_sdapsarray_end_line_flip: % Create next box to store away, this has to be a colhead at this point \sdaps_array_assign_colhead:Nw \l_tmpa_box \bgroup \bool_set_false:N \l__sdaps_sdapsarray_in_top_group_bool \cs_set_eq:NN \\ \cr \tex_ignorespaces:D } \NewDocumentEnvironment { sdapsarray } { o } { \bool_set_false:N \l__sdaps_sdapsarray_in_top_group_bool \group_begin: \tl_set:Nn \l_tmpa_tl { } \IfNoValueF { #1 } { \tl_set:Nn \l_tmpa_tl { #1 } } \box_clear:N \l_tmpa_box \box_clear:N \l_tmpb_box % Ensure vertical mode. \tex_par:D \if_mode_vertical: \else: \msg_error:nn { sdapsarray } { wrong_mode } \fi % This needs to be initialized here as otherwise the values would be % expanded at import time. \keys_set:nV { sdaps / sdapsarray } \l_tmpa_tl \sdaps_array_begin:VV \l_sdaps_sdapsarray_layouter_tl \l_sdaps_sdapsarray_align_tl % Note, this environment is fragile; we redefine & to be active. % One can go back into normal mode by using \sdapsnested{} though. \bool_if:NTF \l_sdaps_sdapsarray_flip_bool { \cs_set_eq:NN \sdaps_array_newline: \_sdaps_sdapsarray_newline_flip: \cs_set_eq:NN \sdaps_array_alignment: \_sdaps_sdapsarray_alignment_flip: \_sdaps_sdapsarray_defines: % Two hboxes to hold the content, note that % a: row headers, b: cells/col headers \box_clear:N \l_sdaps_sdapsarray_headers_box \box_clear:N \l_sdaps_sdapsarray_boxlist_head_box \box_clear:N \l_sdaps_sdapsarray_boxlist_tail_box % not sure why we need this group, but nothing works without it \bgroup % This is a bit creative to say the least \sdaps_array_row_start: \bool_set_true:N \l__sdaps_sdapsarray_in_top_group_bool \sdaps_array_assign_rowhead:Nw \l_tmpa_box \bgroup \bool_set_false:N \l__sdaps_sdapsarray_in_top_group_bool \cs_set_eq:NN \\ \cr % Ignore following spaces by the user \tex_ignorespaces:D } { \cs_set_eq:NN \sdaps_array_newline: \_sdaps_sdapsarray_newline: \cs_set_eq:NN \sdaps_array_alignment: \_sdaps_sdapsarray_alignment: \_sdaps_sdapsarray_defines: \cs_set_eq:NN \_sdaps_sdapsarray_cell:w \sdaps_array_colhead:w \_sdaps_sdapsarray_linestart: } % If we redefine &, then the next character might have the wrong catcode % (i.e. it could still be an alignment character). Execute the alignment % code directly if the next character is &. \bool_if:NF \l_sdaps_sdapsarray_keepenv_bool { \peek_charcode_remove_ignore_spaces:NT & { \sdaps_array_alignment: } } } { \bool_if:NTF \l_sdaps_sdapsarray_flip_bool { \_sdaps_sdapsarray_end_cell_flip: % At this point we should have swallowed all items from the head list. % If not, then someone likely add a stray \\ command or similar \_sdaps_sdapsarray_boxlist_void_if_empty:N \l_sdaps_sdapsarray_boxlist_head_box \box_if_empty:NTF \l_sdaps_sdapsarray_boxlist_head_box { \_sdaps_sdapsarray_end_line_flip: } { \msg_error:nn { sdapsarray } { no_new_line_at_end } } % Now we can have fun! % Pop cells and heading, until we cannot find any new ones. \_sdaps_sdapsarray_pop_last_hbox_unpack:NN \l_tmpa_box \l_sdaps_sdapsarray_headers_box \_sdaps_sdapsarray_pop_last_box:NN \l_tmpb_box \l_sdaps_sdapsarray_boxlist_head_box \bool_do_while:nn { ! \box_if_empty_p:N \l_tmpa_box || ! \box_if_empty_p:N \l_tmpb_box } { \sdaps_array_row:NN \l_tmpa_box \l_tmpb_box \sdaps_array_row_start: \_sdaps_sdapsarray_pop_last_hbox_unpack:NN \l_tmpa_box \l_sdaps_sdapsarray_headers_box \_sdaps_sdapsarray_pop_last_box:NN \l_tmpb_box \l_sdaps_sdapsarray_boxlist_head_box } \egroup } { \egroup \bool_if:NF \l__sdaps_sdapsarray_in_top_group_bool { \msg_error:nnn { sdapsarray } { unmatched_grouping_level } { the~end~of~the~environment } } \egroup % We are in the environment scope again here % Output the last line if the cells were non-empty. \bool_if:NT \l__sdaps_sdapsarray_have_content_bool { \sdaps_array_row:NN \l_tmpa_box \l_tmpb_box } } \sdaps_array_end: \group_end: } \ExplSyntaxOff % % \end{macrocode} % % \Finale \endinput sdaps-1.9.8/tex/class/sdapsarray.ins0000644000175000000660000000354513600505201020167 0ustar benjaminlock00000000000000%% %% Copyright (C) 2015 by Benjamin Berg %% %% This work may be distributed and/or modified under the %% conditions of the LaTeX Project Public License, either version 1.3c %% of this license or (at your option) any later version. %% The latest version of this license is in %% http://www.latex-project.org/lppl.txt %% %% This work has the LPPL maintenance status `maintained'. %% %% The Current Maintainer of this work is Benjamin Berg. %% \input l3docstrip.tex \keepsilent \usedir{tex/latex/cskeleton} \preamble This is a generated file. Copyright (C) 2015 by Benjamin Berg This work may be distributed and/or modified under the conditions of the LaTeX Project Public License, either version 1.3c of this license or (at your option) any later version. The latest version of this license is in http://www.latex-project.org/lppl.txt \endpreamble \generate{\file{sdapsarray.sty}{\from{sdapsarray.dtx}{package}}} \obeyspaces \Msg{*************************************************************} \Msg{* *} \Msg{* To finish the installation you have to move the following *} \Msg{* file into a directory searched by TeX: *} \Msg{* *} \Msg{* sdapsarray.cls *} \Msg{* *} \Msg{* To produce the documentation run the file sdapsarray.dtx *} \Msg{* through LaTeX. *} \Msg{* *} \Msg{* Happy TeXing! *} \Msg{* *} \Msg{*************************************************************} \endbatchfile sdaps-1.9.8/tex/class/sdapsbase.dtx0000644000175000000660000017034113600505201017770 0ustar benjaminlock00000000000000% \iffalse meta-comment % % Copyright (C) 2019 by Benjamin Berg % % This work may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3c % of this license or (at your option) any later version. % The latest version of this license is in % http://www.latex-project.org/lppl.txt % % This work has the LPPL maintenance status `maintained'. % % The Current Maintainer of this work is Benjamin Berg. % % \fi % % \iffalse %<*driver> \ProvidesFile{sdapsbase.dtx} % %\NeedsTeXFormat{LaTeX2e}[1999/12/01] %\ProvidesPackage{sdapsbase} %<*package> [2015/01/14 v0.1 Initial version of SDAPS base package] % % %<*driver> \documentclass{ltxdoc} \usepackage{sdapsbase}[2015/01/14] %\EnableCrossrefs \CodelineIndex \RecordChanges \begin{document} \DocInput{sdapsbase.dtx} \end{document} % % \fi % % \CheckSum{0} % % \CharacterTable % {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z % Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z % Digits \0\1\2\3\4\5\6\7\8\9 % Exclamation \! Double quote \" Hash (number) \# % Dollar \$ Percent \% Ampersand \& % Acute accent \' Left paren \( Right paren \) % Asterisk \* Plus \+ Comma \, % Minus \- Point \. Solidus \/ % Colon \: Semicolon \; Less than \< % Equals \= Greater than \> Question mark \? % Commercial at \@ Left bracket \[ Backslash \\ % Right bracket \] Circumflex \^ Underscore \_ % Grave accent \` Left brace \{ Vertical bar \| % Right brace \} Tilde \~} % % % \changes{v0.1}{2015/01/14}{Initial version} % % \GetFileInfo{sdapsbase.dtx} % % \DoNotIndex{\newcommand,\newenvironment} % % % \title{The \textsf{sdapsbase} package\thanks{This document % corresponds to \textsf{sdapsbase}~\fileversion, dated \filedate.}} % \author{Benjamin Berg \\ \texttt{benjamin@sipsolutions.net}} % % \maketitle % % \section{Documentation} % % Please refer to \url{https://sdaps.org/class-doc} for documentation. % % \StopEventually{\PrintChanges\PrintIndex} % % \section{Implementation} % % This package uses the \LaTeX3 language internally, so we need to enable it. % \begin{macrocode} % We need at least 2011-08-23 for \keys_set_known:nnN \RequirePackage{expl3}[2011/08/23] %\RequirePackage{xparse} \ExplSyntaxOn % \end{macrocode} % % And we need a number of other packages. % \begin{macrocode} \ExplSyntaxOff \input{sdapscode128} \RequirePackage{qrcode} \RequirePackage{tikz} \usetikzlibrary{calc} \usetikzlibrary{positioning} \usetikzlibrary{decorations.pathmorphing} \ExplSyntaxOn % Define aliases for code128 functions, and generate variants \cs_new_eq:NN \code_render:n \code \cs_generate_variant:Nn \code_render:n { x, V } % Also define an alias for the qrcode renderer \cs_new_protected_nopar:Nn \qrcode_render:nn { \qrcode[#1] {#2} } \cs_generate_variant:Nn \qrcode_render:nn { nx, nV } % Define a method to check for RTL languages, as the relevant commands % may not always be defined. \prg_new_conditional:Npnn \sdaps_if_rtl: { p, T, F, TF } { \cs_if_exist:cTF { if@RTL } { \tl_use:c { if@RTL } \prg_return_true: \else \prg_return_false: \fi } { \prg_return_false: } } % \end{macrocode} % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % \subsection{Context Handling} % % When creating complex questionnaires we need a mechnism to handle the current % context. By choice this mechanism works in global scope as items inside a % nested environment (e.g. multicol) need to have an effect on items outside % the environment. Because of this, we implement our own context, which works % similar to TeX groups containing local definitions. % % \begin{macrocode} \cs_generate_variant:Nn \tl_if_eq:nnTF { Vn } \cs_generate_variant:Nn \tl_if_eq:nnT { Vn } \cs_generate_variant:Nn \tl_if_eq:nnF { Vn } \cs_generate_variant:Nn \int_if_odd:nTF { V } \cs_generate_variant:Nn \int_if_odd:nF { V } \cs_generate_variant:Nn \int_if_odd:nT { V } \cs_generate_variant:Nn \tl_set:Nn { Nv } \cs_generate_variant:Nn \msg_error:nnn { nnV } \cs_generate_variant:Nn \exp_not:n { f } \tl_new:N \l__sdaps_tmpa_tl \tl_new:N \l__sdaps_tmpb_tl \dim_new:N \l__sdaps_tmpa_dim % \dim_new:N \l__sdaps_tmpb_dim % \prop_new:N \g__sdaps_current_context_prop \tl_new:N \g__sdaps_current_context_id_tl \tl_new:N \g__sdaps_current_context_tl \seq_new:N \g__sdaps_context_ids_seq \seq_new:N \g__sdaps_contexts_seq % Global metadata write enable variable managed by context \bool_new:N \g_sdaps_write_enable_bool \bool_gset_false:N \g_sdaps_write_enable_bool \cs_new_protected_nopar:Nn \_sdaps_context_to_tl:N { \tl_set:Nx #1 {_write_enable=\bool_if:NTF\g_sdaps_write_enable_bool{\c_true_bool}{\c_false_bool}} \prop_map_inline:Nn \g__sdaps_current_context_prop { % Could we remove some of the braces in the TL? \tl_if_eq:nnTF { \undefined } { ##2 } { \tl_put_right:Nn #1 {,{##1}} } { \tl_put_right:Nn #1 {,{##1}={##2}} } } } % Create new context using given identifier \cs_new_protected_nopar:Nn \sdaps_context_begin:n { % We need to serialize the current context and save it away. \group_begin: % Serialize the current context \_sdaps_context_to_tl:N \l__sdaps_tmpa_tl \tl_gset:NV \g__sdaps_current_context_tl \l__sdaps_tmpa_tl % Stuff it away in our sequence \seq_gput_left:NV \g__sdaps_contexts_seq \g__sdaps_current_context_tl \seq_gput_left:NV \g__sdaps_context_ids_seq \g__sdaps_current_context_id_tl % Clear the hooks \sdaps_context_put:nn { _context_hook_end } {} \sdaps_context_put:nn { _context_hook_post_end } {} \tl_gset:Nn \g__sdaps_current_context_id_tl { #1 } \group_end: } \msg_new:nnn { sdapsbase } { context_end_none_left } { There ~ is ~ no ~ context ~ to ~ end ~ left! } \msg_new:nnn { sdapsbase } { context_end_broken } { The ~ current ~ context ~ with ~ id ~ #1 ~ may ~ not ~ be ~ ended ~ here. } \cs_new_protected_nopar:Nn \__sdaps_context_end: { \seq_if_empty:NTF \g__sdaps_context_ids_seq { \msg_error:nn { sdapsbase } { context_end_none_left } } { \group_begin: \sdaps_context_get:nN { _context_hook_end } \l_tmpa_tl \tl_if_eq:VnF \l_tmpa_tl { \q_no_value } { \tl_use:N \l_tmpa_tl } % Grab post end hook \sdaps_context_get:nN { _context_hook_post_end } \l_tmpa_tl \_sdaps_context_clear: \seq_gpop_left:NN \g__sdaps_contexts_seq \g__sdaps_current_context_tl \seq_gpop_left:NN \g__sdaps_context_ids_seq \l__sdaps_tmpa_tl % Unpack context token list \sdaps_context_set:V \g__sdaps_current_context_tl \sdaps_context_get:nN { _write_enable } \l_tmpb_tl \bool_gset:Nn \g_sdaps_write_enable_bool { \l_tmpb_tl } \sdaps_context_remove:n { _write_enable } \tl_gclear:N \g__sdaps_current_context_tl \tl_gset:NV \g__sdaps_current_context_id_tl \l__sdaps_tmpa_tl \tl_if_eq:VnF \l_tmpa_tl { \q_no_value } { \tl_use:N \l_tmpa_tl } \group_end: } } \bool_new:N \l__sdaps_tmp_bool \cs_new_protected_nopar:Nn \__sdaps_test_context_id:n { \tl_if_eq:VnTF \g__sdaps_current_context_id_tl { #1 } { \bool_set:Nn \l__sdaps_tmp_bool \c_true_bool } { \bool_set:Nn \l__sdaps_tmp_bool \c_false_bool } } % Exit first context with passed in identifier \cs_new_protected_nopar:Nn \sdaps_context_end:n { \__sdaps_test_context_id:n { #1 } \bool_until_do:nn { \l__sdaps_tmp_bool } { \sdaps_context_end: \__sdaps_test_context_id:n { #1 } } \sdaps_context_end: } \cs_new_protected_nopar:Nn \__sdaps_context_end_local_scope: { \__sdaps_test_context_id:n { sdaps_local_scope } \bool_until_do:nn { \l__sdaps_tmp_bool } { \__sdaps_context_end: \__sdaps_test_context_id:n { sdaps_local_scope } } \__sdaps_context_end: } % Exit current context \cs_new_protected_nopar:Nn \sdaps_context_end: { % Ensure the current context is not a local group \tl_if_eq:VnTF \g__sdaps_current_context_id_tl { sdaps_local_scope } { \msg_error:nnV { sdapsbase } { context_end_broken } \g__sdaps_current_context_id_tl } {} \__sdaps_context_end: } % Create new context using an empty name \cs_new_protected_nopar:Nn \sdaps_context_begin: { \sdaps_context_begin:n {} } \cs_new_protected_nopar:Nn \sdaps_context_begin_local: { % Create a new context which will automatically be destroyed at the end of % the current TeX group. \sdaps_context_begin:n { sdaps_local_scope } \group_insert_after:N \__sdaps_context_end_local_scope: } \cs_new_protected_nopar:Nn \sdaps_context_put:n { \sdaps_context_put:nn { #1 } { \undefined } } \cs_new_protected_nopar:Nn \sdaps_context_remove:n { \prop_gremove:Nn \g__sdaps_current_context_prop { #1 } } \msg_new:nnn { sdapsbase } { context_key_broken } { Keys ~ may ~ not ~ contain ~ any ~ special ~ tokens! ~ However ~ the ~ key ~ #1 ~ does ~ contain ~ tokens ~ that ~ are ~ not ~ permissible! } % Directly set a certain key \cs_new_protected_nopar:Nn \sdaps_context_put:nn { % TODO: How can I ensure that {} are not contained? % Though it would not be that bad actually. \tl_if_in:nnTF {#1} {,} { \msg_error:nnn { sdapsbase } { context_key_broken } {#1} } { } \tl_if_in:nnTF {#1} {=} { \msg_error:nnn { sdapsbase } { context_key_broken } {#1} } { } \prop_gput:Nnn \g__sdaps_current_context_prop { #1 } { #2 } } \cs_generate_variant:Nn \sdaps_context_put:nn { nV } % Set a set of keys using comma separated list of key/value pairs \cs_new_protected_nopar:Nn \sdaps_context_set:n { \keyval_parse:NNn \sdaps_context_put:n \sdaps_context_put:nn { #1 } } \cs_generate_variant:Nn \sdaps_context_set:n {V} \cs_new_protected_nopar:Nn \sdaps_context_get:nN { \prop_get:NnN \g__sdaps_current_context_prop { #1 } #2 } \cs_new_protected_nopar:Nn \sdaps_context_gget:nN { \prop_get:NnN \g__sdaps_current_context_prop { #1 } \l_tmpa_tl \tl_gset_eq:NN #2 \l_tmpa_tl } \cs_new_protected_nopar:Nn \sdaps_context_append:nnn { \sdaps_context_get:nN { #1 } \l__sdaps_tmpa_tl \tl_if_eq:VnTF \l__sdaps_tmpa_tl { \q_no_value } { \sdaps_context_put:nn { #1 } { #2 } } { \tl_put_right:Nn \l__sdaps_tmpa_tl { #3 } \tl_put_right:Nn \l__sdaps_tmpa_tl { #2 } \sdaps_context_put:nV { #1 } \l__sdaps_tmpa_tl } } \cs_generate_variant:Nn \sdaps_context_append:nnn { nVn } \cs_new_protected_nopar:Nn \sdaps_context_append:nn { \sdaps_context_append:nnn { #1 } { #2 } { , } } \cs_new_protected_nopar:Nn \sdaps_context_hook_end:n { \sdaps_context_append:nnn { _context_hook_end } { #1 } { } } \cs_new_protected_nopar:Nn \sdaps_context_hook_post_end:n { \sdaps_context_append:nnn { _context_hook_post_end } { #1 } { } } \cs_new_protected_nopar:Nn \sdaps_context_enable_writing: { \bool_gset_true:N \g_sdaps_write_enable_bool } \cs_new_protected_nopar:Nn \sdaps_context_disable_writing: { \bool_gset_false:N \g_sdaps_write_enable_bool } \cs_new_protected_nopar:Nn \_sdaps_context_clear: { \prop_gclear:N \g__sdaps_current_context_prop } \cs_new:Nn \sdaps_context_map_function:N { \prop_map_function:NN \g__sdaps_current_context_prop #1 } \cs_new_protected_nopar:Nn \__sdaps_get:Nn { \prop_get:NnN \g__sdaps_current_context_prop { #2 } #1 } \cs_new_protected_nopar:Nn \__sdaps_get_empty:Nn { \prop_get:NnN \g__sdaps_current_context_prop { #2 } #1 \tl_if_eq:VnT #1 { \q_no_value } { \tl_set:Nn #1 {} } } \cs_new_protected_nopar:Nn \__sdaps_append_from_context:nN { \prop_get:NnN \g__sdaps_current_context_prop { #1 } \l__sdaps_tmpb_tl \tl_if_eq:VnF \l__sdaps_tmpb_tl { \q_no_value } { \tl_put_right:Nn #2 {,} \tl_put_right:NV #2 {\l__sdaps_tmpb_tl} } } \cs_generate_variant:Nn \__sdaps_append_from_context:nN { VN } % \end{macrocode} % % \subsection{Defining Question and Headings} % % SDAPS needs to know about questions and headings/sections. Internally SDAPS % uses the context management system to number these correctly and assign the % variable names including the variable name concatenation automatically. % % Note that the infrastructure present here will not prevent you from nesting % questions, and SDAPS should actually handle this case just fine (ever wanted % to put a question inside a textbox?). % % It is important to keep these balanced. Please note that the SDAPS class does % not use TeX groups here, so you could for example start a context inside a % table and end it outside of it. % % \begin{macrocode} \seq_new:N \g__sdaps_object_id_seq \int_new:N \g__sdaps_object_id_int \int_gzero:N \g__sdaps_object_id_int \cs_new_protected_nopar:Nn \_sdaps_qobject_end_hook: { % Take the current implicit variable \sdaps_context_get:nN { _implicit_var } \l__sdaps_tmpa_tl % Prepend explicit variable name; we assume that either _implicit_var or _var % have a proper value. \sdaps_context_get:nN { _var } \l__sdaps_tmpb_tl \tl_if_eq:VnF \l__sdaps_tmpb_tl { \q_no_value } { \tl_if_eq:VnTF \l__sdaps_tmpa_tl { \q_no_value } { \tl_clear:N \l__sdaps_tmpa_tl } { \tl_put_left:Nn \l__sdaps_tmpa_tl { _ } } \tl_put_left:NV \l__sdaps_tmpa_tl \l__sdaps_tmpb_tl } \sdaps_context_get:nN { id } \l__sdaps_tmpb_tl \tl_if_eq:VnTF \l__sdaps_tmpb_tl { \q_no_value } { \msg_warning:nn { sdapsbase } { no_qid } } { \sdaps_info_write_x:x{ Variable[\l__sdaps_tmpb_tl]=\l__sdaps_tmpa_tl } } } \cs_new_protected_nopar:Nn \_sdaps_qobject_post_hook: { \seq_gpop_right:NN \g__sdaps_object_id_seq \l__sdaps_tmpa_tl \int_gset:NV \g__sdaps_object_id_int \l__sdaps_tmpa_tl } \cs_new_protected_nopar:Nn \sdaps_qobject_begin:nnn { \int_gincr:N \g__sdaps_object_id_int \seq_gput_right:NV \g__sdaps_object_id_seq \g__sdaps_object_id_int \tl_set:Nx \l__sdaps_tmpa_tl { \int_use:N \g__sdaps_object_id_int } \int_gzero:N \g__sdaps_object_id_int \tl_set:Nx \l__sdaps_tmpb_tl { \seq_use:Nn \g__sdaps_object_id_seq {.} } \sdaps_context_begin:n {#1} \sdaps_context_put:nV {id} \l__sdaps_tmpb_tl \sdaps_info_write:x {QObject-#2=\tl_use:N\l__sdaps_tmpb_tl. ~ \exp_not:n{#3}} \sdaps_context_append:nVn { _implicit_var } \l__sdaps_tmpa_tl { _ } \sdaps_context_hook_end:n { \_sdaps_qobject_end_hook: } \sdaps_context_hook_post_end:n { \_sdaps_qobject_post_hook: } } \cs_generate_variant:Nn \sdaps_qobject_begin:nnn { nnV, nVV, nVn } \cs_new_protected_nopar:Nn \sdaps_qobject_end:n { % End the context in question, everything else is done from the close hook \sdaps_context_end:n {#1} } \cs_new_protected_nopar:Nn \sdaps_qobject_begin:nn { \sdaps_qobject_begin:nnn { unnamed_qobject } { #1 } { #2 } } \cs_new_protected_nopar:Nn \sdaps_qobject_begin_local:nn { % Empty local context which automatically closes the qobject \sdaps_context_begin_local: \sdaps_qobject_begin:nnn { unnamed_local_qobject } { #1 } { #2 } } \cs_new_protected_nopar:Nn \sdaps_qobject_end: { \sdaps_qobject_end:n { unnamed_qobject } } \cs_new_protected_nopar:Nn \sdaps_qobject_append_var:n { % If the given variable name starts with _ then include the implicitly % generated variable name. \tl_if_head_eq_charcode:nNTF { #1 } _ { \sdaps_context_get:nN { _implicit_var } \l__sdaps_tmpa_tl \tl_if_eq:VnF \l__sdaps_tmpa_tl { \q_no_value } { \sdaps_context_append:nVn { _var } \l__sdaps_tmpa_tl { _ } } \sdaps_context_append:nnn { _var } { #1 } { } } { \sdaps_context_append:nnn { _var } { #1 } { _ } } % We have a proper variable name now, delete the implicit one \sdaps_context_remove:n { _implicit_var } } \cs_generate_variant:Nn \sdaps_qobject_append_var:n { V } \msg_new:nnn { sdapsbase } { no_qid } { Trying~to~output~metadata~but~no~question~ID~is~set~on~the~context.~Did~you~start~a~question?~Supressing~the~output! } \cs_new_protected_nopar:Nn \sdaps_answer:n { \sdaps_context_get:nN { id } \l__sdaps_tmpa_tl \tl_if_eq:VnTF \l__sdaps_tmpa_tl { \q_no_value } { \msg_warning:nn { sdapsbase } { no_qid } } { \sdaps_info_write:x { Answer[\tl_use:N \l__sdaps_tmpa_tl]=\exp_not:n { #1 } } } } \cs_generate_variant:Nn \sdaps_answer:n { o } \cs_generate_variant:Nn \sdaps_answer:n { f } \cs_generate_variant:Nn \sdaps_answer:n { V } \cs_new_protected_nopar:Nn \sdaps_range:nnn { \sdaps_context_get:nN { id } \l__sdaps_tmpa_tl \tl_if_eq:VnTF \l__sdaps_tmpa_tl { \q_no_value } { \msg_warning:nn { sdapsbase } { no_qid } } { \sdaps_info_write:x { Range-#1[\tl_use:N \l__sdaps_tmpa_tl]=\int_eval:n{#2},\exp_not:n { #3 } } } } \cs_generate_variant:Nn \sdaps_range:nnn { nno } \cs_generate_variant:Nn \sdaps_range:nnn { nnf } \cs_generate_variant:Nn \sdaps_range:nnn { nnV } \cs_generate_variant:Nn \tl_if_head_eq_charcode:nNT { VN } \cs_new_protected_nopar:Nn \_sdaps_generate_var:nN { \tl_set:Nn \l__sdaps_tmpa_tl { #1 } % Generate a variable name if there is none (prepended with _ prefix) \tl_if_empty:VT \l__sdaps_tmpa_tl { \tl_set:Nx \l__sdaps_tmpa_tl { _ \int_eval:n { \g__sdaps_object_id_int + 1 } } } % Prepend any implicitly generated variable names if prefixed by _ \tl_if_head_eq_charcode:VNT \l__sdaps_tmpa_tl _ { \sdaps_context_get:nN { _implicit_var } \l__sdaps_tmpb_tl \tl_if_eq:VnTF \l__sdaps_tmpb_tl { \q_no_value } { \tl_remove_once:Nn \l__sdaps_tmpa_tl { _ } } { \tl_put_left:NV \l__sdaps_tmpa_tl \l__sdaps_tmpb_tl } } % Prepend explicit variable name \sdaps_context_get:nN { _var } \l__sdaps_tmpb_tl \tl_if_eq:VnF \l__sdaps_tmpb_tl { \q_no_value } { \tl_put_left:Nn \l__sdaps_tmpa_tl { _ } \tl_put_left:NV \l__sdaps_tmpa_tl \l__sdaps_tmpb_tl } \tl_set:NV #2 \l__sdaps_tmpa_tl } \cs_new_protected_nopar:Nn \_sdaps_box_inc_object_id: { \bool_if:NT \g_sdaps_write_enable_bool { \int_gincr:N \g__sdaps_object_id_int } } % \end{macrocode} % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % \subsection{Data handling and override specification} % % Often it is useful to set certain flags for specific checkboxes. As the % checkbox may only be generated internally by SDAPS it is impossible to pass % a flag to it directly. Because of this \textsf{sdapsbase} has some mechanisms % to maintain a tree with options. % % \begin{verbatim} % \sdaps_overrides_init:n{*={ % *={}, % checkbox2={ellipse}, % checkbox3,1={width=6mm}, % }} % \end{verbatim} % % \begin{macrocode} \cs_generate_variant:Nn \keyval_parse:NNn { NNV } \cs_generate_variant:Nn \int_gset:Nn { NV } \seq_new:N \g__sdaps_checkbox_overlays_seq \seq_new:N \g__sdaps_textbox_overlays_seq \prop_new:N \g__sdaps_id_to_overrides_prop \prop_new:N \g__sdaps_overrides_prop \prop_new:N \g__sdaps_id_overrides_prop \cs_new_protected_nopar:Nn \__sdaps_questionnaire_overrides_set:nn { \str_if_eq_x:nnTF { #1 } { * } { \__sdaps_parse_overrides:n{ #2 } } { \prop_put:Nnn \g__sdaps_id_to_overrides_prop { #1 } { #2 } } } \cs_new_protected_nopar:Nn \sdaps_overrides_init:n { \keyval_parse:NNn \use_none:n \__sdaps_questionnaire_overrides_set:nn { #1 } } \cs_new_protected_nopar:Nn \__sdaps_overrides_set:nn { \prop_gput:Nnn \g__sdaps_overrides_prop { #1 } { #2 } } \cs_new_protected_nopar:Nn \__sdaps_id_overrides_set:nn { \prop_gput:Nnn \g__sdaps_id_overrides_prop { #1 } { #2 } } \cs_new_protected_nopar:Nn \__sdaps_parse_overrides:n { \prop_gclear:N \g__sdaps_overrides_prop \keyval_parse:NNn \use_none:n \__sdaps_overrides_set:nn { #1 } } \tl_new:N \l__sdaps_set_qid_tl \cs_new_protected_nopar:Nn \sdaps_set_questionnaire_id:n { \tl_gset:Nn \g__sdaps_questionnaire_id_tl { #1 } \prop_gclear:N \g__sdaps_id_overrides_prop \prop_get:NnNT \g__sdaps_id_to_overrides_prop { #1 } \l__sdaps_set_qid_tl { \keyval_parse:NNV \use_none:n \__sdaps_id_overrides_set:nn \l__sdaps_set_qid_tl } } \cs_generate_variant:Nn \sdaps_set_questionnaire_id:n { V } \cs_new_protected_nopar:Nn \__sdaps_append_override_options:Nnn { % Global definition % First generic for all items \prop_get:NnNT \g__sdaps_overrides_prop { * } \l__sdaps_tmpa_tl { \tl_put_right:Nn #1 {,} \tl_put_right:NV #1 \l__sdaps_tmpa_tl } \tl_if_empty:nF { #2 } { % Items with same variable name \prop_get:NnNT \g__sdaps_overrides_prop { #2 } \l__sdaps_tmpa_tl { \tl_put_right:Nn #1 {,} \tl_put_right:NV #1 \l__sdaps_tmpa_tl } \tl_if_empty:nF { #3 } { % Items with same variable name and value \prop_get:NnNT \g__sdaps_overrides_prop { #2 } \l__sdaps_tmpa_tl { \tl_put_right:Nn #1 {,} \tl_put_right:NV #1 \l__sdaps_tmpa_tl } } } % Local (questionnaire ID specific) definition % First generic for all items \prop_get:NnNT \g__sdaps_id_overrides_prop { * } \l__sdaps_tmpa_tl { \tl_put_right:Nn #1 {,} \tl_put_right:NV #1 \l__sdaps_tmpa_tl } \tl_if_empty:nF { #2 } { % Items with same variable name \prop_get:NnNT \g__sdaps_id_overrides_prop { #2 } \l__sdaps_tmpa_tl { \tl_put_right:Nn #1 {,} \tl_put_right:NV #1 \l__sdaps_tmpa_tl } \tl_if_empty:nF { #3 } { % Items with same variable name and value \prop_get:NnNT \g__sdaps_id_overrides_prop { #2 } \l__sdaps_tmpa_tl { \tl_put_right:Nn #1 {,} \tl_put_right:NV #1 \l__sdaps_tmpa_tl } } } } \cs_generate_variant:Nn \__sdaps_append_override_options:Nnn { NVn } % \end{macrocode} % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % First we define constants and global variables for later use. % \begin{macrocode} \dim_new:N \g_sdaps_linewidth_dim \g_sdaps_linewidth_dim=1bp \tl_new:N \g__sdaps_checkbox_last_info_tl \int_new:N \g__sdaps_textbox_num_int \int_set:Nn \g__sdaps_textbox_num_int 0 \tl_new:N \l_sdaps_var_tl \dim_new:N \l_sdaps_x_dim \dim_new:N \l_sdaps_y_dim \dim_new:N \l_sdaps_width_dim \dim_new:N \l_sdaps_height_dim % \end{macrocode} % % We need to be able to output data into the .sdaps file. On startup the % output is opened but writing is disabled. Note that the write enabled % variable is managed by the context. % % \begin{macrocode} \iow_new:N \g_sdaps_infofile_iow \iow_open:Nn \g_sdaps_infofile_iow { \c_sys_jobname_str . sdaps } \int_new:N \g__sdaps_infofile_line_int \int_gset:Nn \g__sdaps_infofile_line_int { 0 } \cs_new_protected_nopar:Nn \sdaps_info_write:n { \bool_if:NT \g_sdaps_write_enable_bool { \int_gincr:N \g__sdaps_infofile_line_int \iow_shipout:Nx \g_sdaps_infofile_iow { [ \int_use:N \g__sdaps_infofile_line_int ] \exp_not:n { #1 } } } } \cs_generate_variant:Nn \sdaps_info_write:n { x } \cs_new_protected_nopar:Nn \sdaps_info_write_x:n { \bool_if:NT \g_sdaps_write_enable_bool { \int_gincr:N \g__sdaps_infofile_line_int \iow_shipout_x:Nx \g_sdaps_infofile_iow { [ \int_use:N \g__sdaps_infofile_line_int ] \exp_not:n { #1 } } } } \cs_generate_variant:Nn \sdaps_info_write_x:n { x } % \end{macrocode} % % Set some options at the beginning of the document. % \begin{macrocode} %\AtBeginDocument{} % \end{macrocode} % % \subsection{Definition for keyword parameters} % % \begin{macrocode} \dim_new:N \l_sdaps_checkbox_linewidth_dim \dim_new:N \l_sdaps_checkbox_width_dim \dim_new:N \l_sdaps_checkbox_height_dim \tl_new:N \l_sdaps_checkbox_form_tl \tl_new:N \l_sdaps_checkbox_fill_tl \tl_new:N \l_sdaps_checkbox_draw_tl \tl_new:N \l_sdaps_checkbox_var_tl \tl_new:N \l_sdaps_checkbox_value_tl \bool_new:N \l_sdaps_checkbox_draw_check_bool \tl_set:Nn \l_sdaps_checkbox_form_tl { box } \tl_new:N \l_sdaps_parse_unknown_tl % Internal overlays \tl_new:N \l_sdaps_overlay_centered_text_tl \tl_new:N \l_sdaps_overlay_minipage_text_tl \tl_new:N \l_sdaps_overlay_minipage_pos_tl \dim_new:N \l_sdaps_overlay_minipage_pad_dim % Note that width/height is the *outside* width/height \keys_define:nn { sdaps / checkbox } { linewidth .dim_set:N = \l_sdaps_checkbox_linewidth_dim, linewidth .initial:n = 1bp, width .dim_set:N = \l_sdaps_checkbox_width_dim, width .initial:n = 3.5mm, height .dim_set:N = \l_sdaps_checkbox_height_dim, height .initial:n = 3.5mm, form .choices:nn = { box, ellipse } { \tl_set:Nx \l_sdaps_checkbox_form_tl { \l_keys_choice_tl } }, value .tl_set:N = \l_sdaps_checkbox_value_tl, fill .tl_set:N = \l_sdaps_checkbox_fill_tl, fill .initial:n = { white }, draw .tl_set:N = \l_sdaps_checkbox_draw_tl, draw .initial:n = { . }, draw_check .bool_set:N = \l_sdaps_checkbox_draw_check_bool, draw_check .default:n = true, draw_check .initial:n = false, % Simple node overlay centered_text .tl_set:N = \l_sdaps_overlay_centered_text_tl, centered_text .initial:n = {}, % minipage overlay text .tl_set:N = \l_sdaps_overlay_minipage_text_tl, text .initial:n = {}, text_align .tl_set:N = \l_sdaps_overlay_minipage_pos_tl, text_align .initial:n = {c}, text_padding .dim_set:N = \l_sdaps_overlay_minipage_pad_dim, text_padding .initial:n = {2bp}, ellipse .meta:n = { form=ellipse }, box .meta:n = { form=box }, } % \end{macrocode} % % \subsection{Checkboxes} % % % \begin{macrocode} \cs_new_protected_nopar:Nn \__sdaps_checkbox_internal:nn { \mbox{ \sdaps_if_rtl:T {\beginL} \pdfsavepos % Position of page and baseline offset \dim_set:Nn \l_sdaps_x_dim { \hoffset } \dim_set:Nn \l_sdaps_y_dim { \voffset + \l_sdaps_checkbox_height_dim - \dim_eval:n { 0.5\l_sdaps_checkbox_height_dim - 0.8ex } } % Size \dim_set:Nn \l_sdaps_width_dim { \l_sdaps_checkbox_width_dim } \dim_set:Nn \l_sdaps_height_dim { \l_sdaps_checkbox_height_dim } \bool_if:NT \g_sdaps_write_enable_bool { % pdflast[xy]pos is the PDF position of the baseline at the start of the box % excluding the page origin offset. \sdaps_context_get:nN {id} \l__sdaps_tmpa_tl \tl_if_eq:VnTF \l__sdaps_tmpa_tl { \q_no_value } { \msg_warning:nn { sdapsbase } { no_qid } } { \sdaps_info_write_x:x{ Box[\l__sdaps_tmpa_tl]=Checkbox, \exp_not:n{\int_use:N\g_sdaps_page_int}, \exp_not:n{\dim_eval:n} { \exp_not:f {\dim_use:N \l_sdaps_x_dim + \the\pdflastxpos sp} }, \exp_not:n{\dim_eval:n} { \exp_not:f {\dim_use:N \l_sdaps_y_dim + \the\pdflastypos sp} }, \dim_use:N \l_sdaps_width_dim, \dim_use:N \l_sdaps_height_dim, \tl_to_str:N\l_sdaps_checkbox_form_tl, \dim_use:N \l_sdaps_checkbox_linewidth_dim, #1,\tl_if_empty:nTF { #2 } { \int_use:N \g__sdaps_object_id_int } { #2 } } } } \tikz[baseline={0.5\l_sdaps_checkbox_height_dim-0.8ex}]{% \tl_if_eq:VnT \l_sdaps_checkbox_form_tl { box } { \draw[line~width=\l_sdaps_checkbox_linewidth_dim,fill=\l_sdaps_checkbox_fill_tl,draw=\l_sdaps_checkbox_draw_tl] (0.5\l_sdaps_checkbox_linewidth_dim, 0.5\l_sdaps_checkbox_linewidth_dim) rectangle +($(\l_sdaps_checkbox_width_dim, \l_sdaps_checkbox_height_dim)-(\l_sdaps_checkbox_linewidth_dim,\l_sdaps_checkbox_linewidth_dim)$);% } \tl_if_eq:VnT \l_sdaps_checkbox_form_tl { ellipse } { \draw[line~width=\l_sdaps_checkbox_linewidth_dim,fill=\l_sdaps_checkbox_fill_tl,draw=\l_sdaps_checkbox_draw_tl] (0.5\l_sdaps_checkbox_width_dim, 0.5\l_sdaps_checkbox_height_dim) circle [x~radius=0.5\l_sdaps_checkbox_width_dim-0.5\l_sdaps_checkbox_linewidth_dim, y~radius=0.5\l_sdaps_checkbox_height_dim-0.5\l_sdaps_checkbox_linewidth_dim];% } % For the overlay we actually position the nodes relative to the checkbox % and not absolute on the page. \dim_set:Nn \l_sdaps_x_dim { 0pt } \dim_set:Nn \l_sdaps_y_dim { \l_sdaps_checkbox_height_dim } % Use overlay so that nothing happens if a node is larger than the checkbox \begin{scope}[overlay] \seq_map_inline:Nn \g__sdaps_checkbox_overlays_seq {##1} \end{scope} } \sdaps_if_rtl:T {\endL} } } \cs_generate_variant:Nn \__sdaps_checkbox_internal:nn { Vn } \sdaps_context_set:n { checkboxtype=multichoice } \cs_new_protected_nopar:Nn \sdaps_checkbox_set_type:n { \sdaps_context_set:n { checkboxtype={#1} } } \cs_generate_variant:Nn \sdaps_checkbox_set_type:n { V } \cs_new_protected_nopar:Nn \sdaps_checkbox:nn { \group_begin:% \_sdaps_generate_var:nN { #1 } \l_sdaps_var_tl \sdaps_context_get:nN { checkboxtype } \l__sdaps_tmpa_tl \tl_if_eq:VnTF \l__sdaps_tmpa_tl { multichoice } { \tl_set:Nn \l_sdaps_parse_unknown_tl { box } } { \tl_set:Nn \l_sdaps_parse_unknown_tl { ellipse } } \__sdaps_append_from_context:nN { * } \l_sdaps_parse_unknown_tl \__sdaps_append_from_context:VN \l__sdaps_tmpa_tl \l_sdaps_parse_unknown_tl \__sdaps_append_override_options:NVn \l_sdaps_parse_unknown_tl \l_sdaps_var_tl { #2 } \keys_set_known:nVN { sdaps / checkbox } \l_sdaps_parse_unknown_tl \l_sdaps_parse_unknown_tl \_sdaps_box_inc_object_id: \__sdaps_checkbox_internal:Vn \l_sdaps_var_tl { #2 } \group_end:% \ignorespaces } \cs_generate_variant:Nn \sdaps_checkbox:nn { Vn, VV, nV } \cs_new_protected_nopar:Nn \sdaps_overlay_check: { \bool_if:NT \l_sdaps_checkbox_draw_check_bool { \begin{scope}[decoration={random~steps,segment~length=4pt,amplitude=1pt}] \draw[line~width=\l_sdaps_checkbox_linewidth_dim, decorate] ($(0, 0) - (2pt,2pt)$) -- (0.5\l_sdaps_checkbox_width_dim, 0.5\l_sdaps_checkbox_height_dim) -- ($(\l_sdaps_checkbox_width_dim, \l_sdaps_checkbox_height_dim) + (2pt,2pt)$);% \draw[line~width=\l_sdaps_checkbox_linewidth_dim, decorate] ($(0, \l_sdaps_checkbox_height_dim) + (-2pt,2pt)$) -- (0.5\l_sdaps_checkbox_width_dim, 0.5\l_sdaps_checkbox_height_dim) -- ($(\l_sdaps_checkbox_width_dim, 0) + (2pt,-2pt)$);% \end{scope} } } \seq_put_left:Nn \g__sdaps_checkbox_overlays_seq \sdaps_overlay_check: \cs_new_protected_nopar:Nn \sdaps_overlay_centered: { \tl_if_empty:NF \l_sdaps_overlay_centered_text_tl { \node[anchor=center,inner~sep=0pt,outer~sep=0pt] at ($(\l_sdaps_x_dim, \l_sdaps_y_dim) + 0.5*(\l_sdaps_width_dim, -\l_sdaps_height_dim)$) { \l_sdaps_overlay_centered_text_tl }; } } \seq_put_left:Nn \g__sdaps_checkbox_overlays_seq \sdaps_overlay_centered: \seq_put_left:Nn \g__sdaps_textbox_overlays_seq \sdaps_overlay_centered: \cs_new_protected_nopar:Nn \sdaps_overlay_minipage: { \tl_if_empty:NF \l_sdaps_overlay_minipage_text_tl { \node[anchor=center,inner~sep=0pt,outer~sep=0pt] at ($(\l_sdaps_x_dim, \l_sdaps_y_dim) + 0.5*(\l_sdaps_width_dim, -\l_sdaps_height_dim)$) { \dim_set:Nn \l_sdaps_width_dim { \l_sdaps_width_dim - 2\l_sdaps_overlay_minipage_pad_dim } \dim_set:Nn \l_sdaps_height_dim { \l_sdaps_height_dim - 2\l_sdaps_overlay_minipage_pad_dim } \begin{minipage}[t][\l_sdaps_height_dim][\l_sdaps_overlay_minipage_pos_tl]{\l_sdaps_width_dim} % Hm, is this sane? \tex_let:D \textheight\l_sdaps_height_dim \l_sdaps_overlay_minipage_text_tl \end{minipage} }; } } \seq_put_left:Nn \g__sdaps_checkbox_overlays_seq \sdaps_overlay_minipage: \seq_put_left:Nn \g__sdaps_textbox_overlays_seq \sdaps_overlay_minipage: % \end{macrocode} % % \subsection{Textboxes} % % % \begin{macrocode} \sdaps_context_set:n { textboxtype=textbox } \cs_new_protected_nopar:Nn \sdaps_textbox_set_type:n { \sdaps_context_set:n { textboxtype={#1} } } \cs_generate_variant:Nn \sdaps_textbox_set_type:n { V } \dim_new:N \l_sdaps_textbox_linewidth_dim \tl_new:N \l_sdaps_textbox_var_tl \tl_new:N \l_sdaps_textbox_fill_tl \tl_new:N \l_sdaps_textbox_draw_tl \tl_new:N \l__sdaps_textbox_boxtype_tl \keys_define:nn { sdaps / textbox } { linewidth .dim_set:N = \l_sdaps_textbox_linewidth_dim, linewidth .initial:n = 1bp, fill .tl_set:N = \l_sdaps_textbox_fill_tl, fill .initial:n = { white }, draw .tl_set:N = \l_sdaps_textbox_draw_tl, draw .initial:n = { . }, % Simple node overlay centered_text .tl_set:N = \l_sdaps_overlay_centered_text_tl, centered_text .initial:n = {}, % minipage overlay text .tl_set:N = \l_sdaps_overlay_minipage_text_tl, text .initial:n = {}, text_align .tl_set:N = \l_sdaps_overlay_minipage_pos_tl, text_align .initial:n = {c}, text_padding .dim_set:N = \l_sdaps_overlay_minipage_pad_dim, text_padding .initial:n = {2bp}, } \dim_new:N \l__sdaps_textbox_dp_dim \dim_new:N \l__sdaps_textbox_ht_dim \dim_new:N \l__sdaps_textbox_wd_dim \dim_new:N \l__sdaps_textbox_pad_dim \msg_new:nnn { sdapsbase } { textbox_wrong_mode } { Impossible~to~layout~a~#1~textbox~in~#2~mode. } \cs_new_protected_nopar:Nn \__sdaps_textbox_prepare:n { \tl_set:Nn \l_sdaps_parse_unknown_tl {} \_sdaps_generate_var:nN { #1 } \l_sdaps_var_tl \sdaps_context_get:nN { textboxtype } \l__sdaps_tmpa_tl \tl_if_eq:VnTF \l__sdaps_tmpa_tl { codebox } { \tl_set:Nn \l__sdaps_textbox_boxtype_tl { Codebox } } { \tl_set:Nn \l__sdaps_textbox_boxtype_tl { Textbox } } \__sdaps_append_from_context:nN { * } \l_sdaps_parse_unknown_tl \__sdaps_append_from_context:VN \l__sdaps_tmpa_tl \l_sdaps_parse_unknown_tl \__sdaps_append_override_options:NVn \l_sdaps_parse_unknown_tl \l_sdaps_var_tl { } \keys_set_known:nVN { sdaps / textbox } \l_sdaps_parse_unknown_tl \l_sdaps_parse_unknown_tl \_sdaps_box_inc_object_id: } \cs_new_protected_nopar:Nn \sdaps_textbox_vhstretch:nnn { % \end{macrocode} % % At first we need to ensure that we are not in math mode. We also error out if % switching into vertical mode (by inserting a paragraph break) fails. % % The scaling feature will likely fail in inner vertical mode, but it is still % permissible. % % \begin{macrocode} \if_mode_math: \msg_error:nnnn { sdapsbase } { textbox_wrong_mode } { vhstretch } { math } \else: \tex_par:D \if_mode_horizontal: \msg_error:nnnn { sdapsbase } { textbox_wrong_mode } { vhstretch } { horizontal } \else: % Go into vertical mode by ending the current paragraph and insert % \cs{widowpenalty} so that we don't get an unwelcome page break. It is % assumed that any explanation for the textbox will be on top. \tex_penalty:D \tex_widowpenalty:D \group_begin:% \__sdaps_textbox_prepare:n { #1 } % \end{macrocode} % % First we define the height and depth of the box that will be set. Setting the % height works by inserting a rule into the first box and adding a negative % skip afterwards. The depth is compensated by simply doing the same thing at % the bottom. % % Note that we need to add nobreak/nointerlineskip everywhere so that we % don't insert extra spacing and no page break will happen. % % The first box has a defined height and stores the current position for the % frame code later on. Then two cleaders follow which simply implement the % required stretching (cleaders are used to prevent page breaking, I do not % know whether this is sane, but it seems to work just fine). After this the % box containing the main drawing code is placed. We simply use a vbox with % right aligned content. The last thing happening is a vskip plus hbox to set % the correct depth. % % \begin{macrocode} % TODO: Make this configurable \dim_set:Nn \l__sdaps_textbox_dp_dim { 0.5ex } \dim_set:Nn \l__sdaps_textbox_ht_dim { 1.7ex } \vbox:n { \sdaps_if_rtl:T {\beginL} \leftskip=0pt \rightskip=0pt plus 1fill \noindent \tex_vrule:D height \l__sdaps_textbox_ht_dim depth 0pt width 0pt \pgfsys@markposition{textboxtop\int_use:N\g__sdaps_textbox_num_int} \sdaps_if_rtl:T {\endL} } \tex_penalty:D 10000 \nointerlineskip \tex_cleaders:D\tex_hbox:D{}\skip_vertical:n{#2 - \l__sdaps_textbox_ht_dim} \tex_penalty:D 10000 \nointerlineskip \tex_cleaders:D\tex_hbox:D{}\skip_vertical:n{\stretch{#3}} \tex_penalty:D 10000 \nointerlineskip \vbox:n { \sdaps_if_rtl:T {\beginL} \noindent \leftskip=0pt plus 1fill \rightskip=0pt \begin{tikzpicture}[remember~picture,overlay,shift=(current~page.south~west)] \pgfsys@getposition{pgfpageorigin}{\@sdaps@pageorigin} \pgfsys@getposition{textboxtop\int_use:N\g__sdaps_textbox_num_int}{\@sdaps@textboxtoppos} \pgfpointadd{\@sdaps@textboxtoppos}{ \pgfpointadd{\@sdaps@pageorigin}{\pgfpoint{0}{\l__sdaps_textbox_ht_dim}} } \pgfgetlastxy{\l__sdaps_x}{\l__sdaps_y} \dim_set:Nn \l_sdaps_x_dim {\l__sdaps_x} \dim_set:Nn \l_sdaps_y_dim {\l__sdaps_y} \pgfsys@getposition{\pgfpictureid}{\@sdaps@textboxbottompos} \pgfpointdiff{\@sdaps@textboxtoppos}{\@sdaps@textboxbottompos} % Is there a more elegant way to multiply the height with -1? \pgfgetlastxy{\l__sdaps_width}{\l__sdaps_height} % Add the minimum height (i.e. depth below the last baseline) to the % overall height. \pgfpoint{\l__sdaps_width}{-\l__sdaps_height + \l__sdaps_textbox_ht_dim} \pgfgetlastxy{\l__sdaps_width}{\l__sdaps_height} \dim_set:Nn \l_sdaps_width_dim {\l__sdaps_width} \dim_set:Nn \l_sdaps_height_dim {\l__sdaps_height} % Draw the rectangle \draw[line~width=\l_sdaps_textbox_linewidth_dim,fill=\l_sdaps_textbox_fill_tl,draw=\l_sdaps_textbox_draw_tl] ($(\l_sdaps_x_dim, \l_sdaps_y_dim) + 0.5 * (\l_sdaps_textbox_linewidth_dim, -\l_sdaps_textbox_linewidth_dim)$) rectangle +($(\l_sdaps_width_dim, -\l_sdaps_height_dim) - (\l_sdaps_textbox_linewidth_dim, -\l_sdaps_textbox_linewidth_dim)$); \begin{scope} \seq_map_inline:Nn \g__sdaps_textbox_overlays_seq {##1} \end{scope} \bool_if:NT \g_sdaps_write_enable_bool { \sdaps_context_get:nN {id} \l__sdaps_tmpa_tl \tl_if_eq:VnTF \l__sdaps_tmpa_tl { \q_no_value } { \msg_warning:nn { sdapsbase } { no_qid } } { \sdaps_info_write_x:x { Box[\l__sdaps_tmpa_tl]=\l__sdaps_textbox_boxtype_tl, \exp_not:n{\int_use:N\g_sdaps_page_int}, \dim_use:N \l_sdaps_x_dim, \dim_use:N \l_sdaps_y_dim, \dim_use:N \l_sdaps_width_dim, \dim_use:N \l_sdaps_height_dim, \dim_use:N \l_sdaps_textbox_linewidth_dim, \tl_use:N \l_sdaps_var_tl, } } } \end{tikzpicture} \sdaps_if_rtl:T {\endL} } % We are done here, but we need the correct depth, so skip around a bit \tex_penalty:D 10000 \nointerlineskip \skip_vertical:n{ - \l__sdaps_textbox_dp_dim} \tex_penalty:D 10000 \nointerlineskip \hbox:n { \vrule depth \l__sdaps_textbox_dp_dim height 0pt width 0pt } \int_gincr:N\g__sdaps_textbox_num_int \group_end: \fi: \fi: } \cs_generate_variant:Nn \sdaps_textbox_vhstretch:nnn { Vnn } \cs_new_protected_nopar:Nn \sdaps_textbox_vhstretch:nn { \sdaps_textbox_vhstretch:nnn { #1 } { #2 } { 1 } } \cs_new_protected_nopar:Nn \sdaps_textbox_hstretch:nnnnn { \group_begin: \sdaps_if_rtl:T {\beginL} \__sdaps_textbox_prepare:n { #1 } \dim_set:Nn \l_tmpa_dim { #2 } \dim_set:Nn \l_tmpb_dim { #3 } % Place a vrule to make space for the top/bottom padding \tex_vrule:D depth \dim_use:N \l_tmpa_dim height \dim_use:N \l_tmpb_dim width 0pt \nobreak \pgfsys@markposition{textboxstart\int_use:N\g__sdaps_textbox_num_int} \nobreak \skip_horizontal:n { #4 + \stretch{#5} } \nobreak % The textbox (rendered on the background) \begin{tikzpicture}[remember~picture,overlay,shift=(current~page.south~west)] \pgfsys@getposition{pgfpageorigin}{\@sdaps@pageorigin} \pgfsys@getposition{textboxstart\int_use:N\g__sdaps_textbox_num_int}{\@sdaps@textboxpos} % The position here is the position of the baseline. % So move up by height (param 2) to get the correct vertical position. \pgfpointadd{\@sdaps@textboxpos}{ \pgfpointadd{\@sdaps@pageorigin}{\pgfpoint{0}{ \dim_use:N \l_tmpb_dim}} } \pgfgetlastxy{\l__sdaps_x}{\l__sdaps_y} \dim_set:Nn \l_sdaps_x_dim {\l__sdaps_x} \dim_set:Nn \l_sdaps_y_dim {\l__sdaps_y} \pgfsys@getposition{\pgfpictureid}{\@sdaps@textboxendpos} % Calculate width and add the height to it \pgfpointadd{ \pgfpointdiff{\@sdaps@textboxpos}{\@sdaps@textboxendpos} }{\pgfpoint{0pt}{\dim_use:N \l_tmpa_dim + \dim_use:N \l_tmpb_dim}} \pgfgetlastxy{\l__sdaps_width}{\l__sdaps_height} \dim_set:Nn \l_sdaps_width_dim {\l__sdaps_width} \dim_set:Nn \l_sdaps_height_dim {\l__sdaps_height} % Draw the rectangle \draw[line~width=\l_sdaps_textbox_linewidth_dim,fill=\l_sdaps_textbox_fill_tl,draw=\l_sdaps_textbox_draw_tl] ($(\l_sdaps_x_dim, \l_sdaps_y_dim) + 0.5 * (\l_sdaps_textbox_linewidth_dim, -\l_sdaps_textbox_linewidth_dim)$) rectangle +($(\l_sdaps_width_dim, -\l_sdaps_height_dim) - (\l_sdaps_textbox_linewidth_dim, -\l_sdaps_textbox_linewidth_dim)$); \begin{scope} \seq_map_inline:Nn \g__sdaps_textbox_overlays_seq {##1} \end{scope} \bool_if:NT \g_sdaps_write_enable_bool { \sdaps_context_get:nN {id} \l__sdaps_tmpa_tl \tl_if_eq:VnTF \l__sdaps_tmpa_tl { \q_no_value } { \msg_warning:nn { sdapsbase } { no_qid } } { \sdaps_info_write_x:x { Box[\l__sdaps_tmpa_tl]=\l__sdaps_textbox_boxtype_tl, \exp_not:n{\int_use:N\g_sdaps_page_int}, \dim_use:N \l_sdaps_x_dim, \dim_use:N \l_sdaps_y_dim, \dim_use:N \l_sdaps_width_dim, \dim_use:N \l_sdaps_height_dim, \dim_use:N \l_sdaps_textbox_linewidth_dim, \tl_use:N \l_sdaps_var_tl, } } } \end{tikzpicture} \int_gincr:N\g__sdaps_textbox_num_int \sdaps_if_rtl:T {\endL} \group_end: } \cs_new_protected_nopar:Nn \__sdaps_textbox_prepare_coffin: { \dim_set:Nn \l__sdaps_textbox_ht_dim { \coffin_ht:N \l__sdaps_textbox_coffin } \dim_set:Nn \l__sdaps_textbox_dp_dim { \coffin_dp:N \l__sdaps_textbox_coffin } \dim_set:Nn \l__sdaps_textbox_wd_dim { \coffin_wd:N \l__sdaps_textbox_coffin } \hcoffin_set:Nn \l_tmpa_coffin { \tex_vrule:D depth 0pt height \dim_eval:n { \l__sdaps_textbox_ht_dim + \l__sdaps_textbox_pad_dim } width 0pt \pdfsavepos \dim_set:Nn \l_sdaps_width_dim {\l__sdaps_textbox_wd_dim + 2\l__sdaps_textbox_pad_dim} \dim_set:Nn \l_sdaps_height_dim {\l__sdaps_textbox_ht_dim + \l__sdaps_textbox_dp_dim + 2\l__sdaps_textbox_pad_dim} % pdflast[xy]pos is the PDF position of the top left corner excluding the % origin \bool_if:NT \g_sdaps_write_enable_bool { \sdaps_context_get:nN {id} \l__sdaps_tmpa_tl \tl_if_eq:VnTF \l__sdaps_tmpa_tl { \q_no_value } { \msg_warning:nn { sdapsbase } { no_qid } } { \sdaps_info_write_x:x { Box[\l__sdaps_tmpa_tl]=\l__sdaps_textbox_boxtype_tl, \exp_not:n{\int_use:N\g_sdaps_page_int}, \exp_not:n{\dim_eval:n {\hoffset + \the\pdflastxpos sp}}, \exp_not:n{\dim_eval:n} { \exp_not:n {\voffset + \the\pdflastypos sp} + \dim_use:N \l__sdaps_textbox_ht_dim + \dim_use:N \l__sdaps_textbox_pad_dim }, \dim_use:N \l_sdaps_width_dim, \dim_use:N \l_sdaps_height_dim, \dim_use:N \l_sdaps_textbox_linewidth_dim, \tl_use:N \l_sdaps_var_tl, } } } \dim_set:Nn \l_sdaps_x_dim { 0pt } \dim_set:Nn \l_sdaps_y_dim { \l__sdaps_textbox_ht_dim + \l__sdaps_textbox_pad_dim } % The textbox (rendered on the background) \begin{tikzpicture}[overlay] % Draw the rectangle \draw[line~width=\l_sdaps_textbox_linewidth_dim,fill=\l_sdaps_textbox_fill_tl,draw=\l_sdaps_textbox_draw_tl] ($(\l_sdaps_x_dim, \l_sdaps_y_dim) + 0.5 * (\l_sdaps_textbox_linewidth_dim, -\l_sdaps_textbox_linewidth_dim)$) rectangle +($(\l_sdaps_width_dim, -\l_sdaps_height_dim) - (\l_sdaps_textbox_linewidth_dim, -\l_sdaps_textbox_linewidth_dim)$); \begin{scope} \seq_map_inline:Nn \g__sdaps_textbox_overlays_seq {##1}% \end{scope} \end{tikzpicture} \skip_horizontal:n { \l__sdaps_textbox_pad_dim } } \hcoffin_set:Nn \l_tmpb_coffin { \skip_horizontal:n { \l__sdaps_textbox_pad_dim } \tex_vrule:D depth \l__sdaps_textbox_pad_dim height 0pt width 0pt } \coffin_join:NnnNnnnn \l_tmpa_coffin { r } { H } \l__sdaps_textbox_coffin { l } { H } { 0pt } { 0pt } \coffin_join:NnnNnnnn \l_tmpa_coffin { r } { b } \l_tmpb_coffin { l } { t } { 0pt } { 0pt } \coffin_set_eq:NN \l__sdaps_textbox_coffin \l_tmpa_coffin \int_gincr:N\g__sdaps_textbox_num_int } \coffin_new:N \l__sdaps_textbox_coffin \cs_new_protected_nopar:Nn \sdaps_textbox_hbox:nnn { \group_begin: \__sdaps_textbox_prepare:n { #1 } \hcoffin_set:Nn \l__sdaps_textbox_coffin { \tl_trim_spaces:n { #3 } } \dim_set:Nn \l__sdaps_textbox_pad_dim { #2 } \__sdaps_textbox_prepare_coffin: \coffin_typeset:Nnnnn \l__sdaps_textbox_coffin { l } { H } { 0pt } { 0pt } \group_end: } \cs_new_protected:Nn \sdaps_textbox_vbox:nnnn { \group_begin: \__sdaps_textbox_prepare:n { #1 } \dim_set:Nn \l__sdaps_textbox_pad_dim { #3 } \dim_set:Nn \l__sdaps_textbox_wd_dim { #2 - 2\l__sdaps_textbox_pad_dim } \vcoffin_set:Nnn \l__sdaps_textbox_coffin { \l__sdaps_textbox_wd_dim } { \tl_trim_spaces:n { #4 }} \__sdaps_textbox_prepare_coffin: \coffin_typeset:Nnnnn \l__sdaps_textbox_coffin { l } { H } { 0pt } { 0pt } \group_end: } % \end{macrocode} % % % \subsection{Page Marking} % % SDAPS depends on certain markings on every page. The following function % implement drawing these marks. % % \begin{macrocode} \int_new:N \g_sdaps_page_int \int_set:Nn \g_sdaps_page_int { 0 } % Disabling recognition disables all drawings related to automatic recognition \bool_new:N \g_sdaps_recognition_bool \bool_new:N \g_sdaps_draft_bool \bool_new:N \g_sdaps_twoside_bool \bool_new:N \g_sdaps_print_questionnaire_id_bool \bool_set:Nn \g_sdaps_recognition_bool \c_true_bool \bool_set:Nn \g_sdaps_draft_bool \c_true_bool \bool_set:Nn \g_sdaps_twoside_bool \c_false_bool \bool_set:Nn \g_sdaps_print_questionnaire_id_bool \c_false_bool \tl_new:N \g_sdaps_style_tl \tl_new:N \g_sdaps_checkmode_tl \dim_new:N \g_sdaps_edge_left_margin_dim \dim_new:N \g_sdaps_edge_right_margin_dim \dim_new:N \g_sdaps_edge_top_margin_dim \dim_new:N \g_sdaps_edge_bottom_margin_dim \dim_new:N \g_sdaps_edge_marker_linewidth_dim \dim_new:N \g_sdaps_edge_marker_length_dim \dim_new:N \g_sdaps_classic_boxpad_dim \dim_new:N \g_sdaps_classic_boxsize_dim \tl_gset:Nn \g_sdaps_style_tl { code128 } \tl_gset:Nn \g_sdaps_twoside_barcode_tl { both } \tl_gset:Nn \g_sdaps_checkmode_tl { checkcorrect } \dim_gset:Nn \g_sdaps_edge_left_margin_dim { 10mm } \dim_gset:Nn \g_sdaps_edge_right_margin_dim { 10mm } \dim_gset:Nn \g_sdaps_edge_top_margin_dim { 12mm } \dim_gset:Nn \g_sdaps_edge_bottom_margin_dim { 12mm } \dim_gset:Nn \g_sdaps_edge_marker_linewidth_dim { 1bp } \dim_gset:Nn \g_sdaps_edge_marker_length_dim { 20mm } \dim_gset:Nn \g_sdaps_classic_boxpad_dim { 3mm } \dim_gset:Nn \g_sdaps_classic_boxsize_dim { 3.5mm } \tl_new:N \g__sdaps_questionnaire_id_tl \tl_gset:Nn \g__sdaps_questionnaire_id_tl { } \tl_new:N \g_sdaps_questionnaire_id_label_tl \tl_gset:Nn \g_sdaps_questionnaire_id_label_tl { } \tl_new:N \g_sdaps_survey_id_tl \tl_gset:Nn \g_sdaps_survey_id_tl { 32498923 } \tl_new:N \g_sdaps_global_id_tl \tl_gset:Nn \g_sdaps_global_id_tl { } \tl_new:N \g_sdaps_global_id_label_tl \tl_gset:Nn \g_sdaps_global_id_label_tl { } % Settings for code128 barcodes (used in code128 style, who would have thought?) \dim_new:N \c_sdaps_barcode_height_dim \dim_gset:Nn \c_sdaps_barcode_height_dim {6.5mm} % This is the same as the default \dim_new:N \c_sdaps_barcode_bar_width_dim \dim_gset:Nn \c_sdaps_barcode_bar_width_dim {0.33mm} % Same as default. Barwidth is decreased for printing by this value. \dim_new:N \c_sdaps_barcode_bcorr_dim \dim_gset:Nn \c_sdaps_barcode_bcorr_dim {0.020mm} % The padding on the left/right of a barcode. This is the distance that the % barcodes will be printed from the cornermarks % Choosen to be the same as the barcode height. Note that the Code-128 % standard requires a quiet zone of max(10*modulesize, ~6.4mm). \dim_new:N \c_sdaps_barcode_hpad_dim \dim_gset:Nn \c_sdaps_barcode_hpad_dim {6.5mm} % This needs to be smaller than 6.5mm because otherwise the content is too close. % We set it so that it forms a golden ratio 6.5mm*(sqrt(5/4)-0.5). This means % we have about 4.5mm padding to the content. \dim_new:N \c_sdaps_barcode_vpad_dim \dim_gset:Nn \c_sdaps_barcode_vpad_dim {4.02mm} \cs_new_protected_nopar:Nn \sdaps_draw_codes: { \group_begin: \begin{scope}[line~width=\g_sdaps_edge_marker_linewidth_dim, shift={(current~page.south~west)}] \str_if_eq:VnT \g_sdaps_style_tl { qr } { \tl_if_empty:VF \g__sdaps_questionnaire_id_tl { \begin{scope}[shift={($(\g_sdaps_edge_left_margin_dim, \g_sdaps_edge_bottom_margin_dim)$)}] \node(barcode)[anchor=south~west,outer~sep=0,inner~sep=0]{ \qrcode_render:nV {nolink,version=2,level=H,padding,height=10mm} \g__sdaps_questionnaire_id_tl }; \end{scope} } % We unconditionally print this barcode, it is required for the recognition % process. \begin{scope}[shift={($(\paperwidth, 0) + (-\g_sdaps_edge_right_margin_dim, \g_sdaps_edge_bottom_margin_dim)$)}] \pgfmathsetbasenumberlength{4} \pgfmathdectobase{\paddedpage}{\int_use:N\g_sdaps_page_int}{10}% Yes, padding to 4 chars the hard way \node(barcode)[anchor=south~east,outer~sep=0,inner~sep=0]{ \qrcode_render:nx {nolink,version=2,level=H,padding,height=10mm} {\tl_use:N\g_sdaps_survey_id_tl\paddedpage} }; \end{scope} \tl_if_empty:VF \g_sdaps_global_id_tl { \begin{scope}[shift={($(\paperwidth/2-\g_sdaps_edge_right_margin_dim/2+\g_sdaps_edge_left_margin_dim/2, \g_sdaps_edge_bottom_margin_dim)$)}] \node(barcode)[anchor=south,outer~sep=0,inner~sep=0]{ \qrcode_render:nV {nolink,version=2,level=H,padding,height=10mm} \g_sdaps_global_id_tl }; \end{scope} } } \str_if_eq:VnT \g_sdaps_style_tl { code128 } { \tl_if_empty:VF \g__sdaps_questionnaire_id_tl { % TODO: do not hardcode the font! \ttfamily\footnotesize \begin{scope}[shift={($(\g_sdaps_edge_left_margin_dim, \g_sdaps_edge_bottom_margin_dim) + (\c_sdaps_barcode_hpad_dim, \c_sdaps_barcode_vpad_dim)$)}] \node(barcode)[anchor=south~west,outer~sep=0,inner~sep=0]{ \X = \c_sdaps_barcode_bar_width_dim \bcorr = \c_sdaps_barcode_bcorr_dim \barheight = \c_sdaps_barcode_height_dim \code_render:V \g__sdaps_questionnaire_id_tl }; \node[below=1mm~of~barcode,distance=0,anchor=north,outer~sep=0,inner~sep=0]{ \tl_if_empty:VTF \g_sdaps_questionnaire_id_label_tl { \tl_use:N \g__sdaps_questionnaire_id_tl } { \tl_use:N \g_sdaps_questionnaire_id_label_tl } }; \end{scope} } % We unconditionally print this barcode, it is required for the recognition % process. \begin{scope}[shift={($(\paperwidth, 0) + (-\g_sdaps_edge_right_margin_dim, \g_sdaps_edge_bottom_margin_dim) + (-\c_sdaps_barcode_hpad_dim, \c_sdaps_barcode_vpad_dim)$)}] \pgfmathsetbasenumberlength{4} \pgfmathdectobase{\paddedpage}{\int_use:N\g_sdaps_page_int}{10}% Yes, padding to 4 chars the hard way \node(barcode)[anchor=south~east,outer~sep=0,inner~sep=0]{ \X = \c_sdaps_barcode_bar_width_dim \bcorr = \c_sdaps_barcode_bcorr_dim \barheight = \c_sdaps_barcode_height_dim \code_render:x {\tl_use:N\g_sdaps_survey_id_tl \paddedpage} }; \node[below=1mm~of~barcode,distance=0,anchor=north,outer~sep=0,inner~sep=0]{ % TODO: do not hardcode the font! \ttfamily\footnotesize \tl_use:N\g_sdaps_survey_id_tl\,\paddedpage }; \end{scope} \tl_if_empty:VF \g_sdaps_global_id_tl { \begin{scope}[shift={($(\paperwidth/2-\g_sdaps_edge_right_margin_dim/2+\g_sdaps_edge_left_margin_dim/2, 0) + (0, \g_sdaps_edge_bottom_margin_dim) + (0, \c_sdaps_barcode_vpad_dim)$)}] \node(barcode)[anchor=south,outer~sep=0,inner~sep=0]{ \X = \c_sdaps_barcode_bar_width_dim \bcorr = \c_sdaps_barcode_bcorr_dim \barheight = \c_sdaps_barcode_height_dim \code_render:V \g_sdaps_global_id_tl }; \node[below=1mm~of~barcode,distance=0,anchor=north,outer~sep=0,inner~sep=0]{ % TODO: do not hardcode the font! \ttfamily\footnotesize \tl_if_empty:VTF \g_sdaps_global_id_label_tl { \tl_use:N \g_sdaps_global_id_tl } { \tl_use:N \g_sdaps_global_id_label_tl } }; \end{scope} } } \end{scope}% \group_end: } \msg_new:nnn { sdapsbase } { classic_too_many_pages } { You~cannot~have~more~than~six~pages~with~the~classic~style. } \msg_new:nnn { sdapsbase } { odd_page_count } { You~have~an~odd~number~of~pages,~this~does~not~work~in~duplex~mode! } % This needs to be called once for each page! \cs_new_protected_nopar:Nn \sdaps_page_end: { \bool_if:NTF \g_sdaps_recognition_bool { \group_begin: \int_gincr:N\g_sdaps_page_int% \sdaps_info_write:x{Pages=\int_use:N\g_sdaps_page_int} \normalfont% \begin{tikzpicture}[remember~picture,overlay]% %--------------------------------------------------------------------------- % corner marks and corner boxes in classic mode %--------------------------------------------------------------------------- \begin{scope}[line~width=\g_sdaps_edge_marker_linewidth_dim, line~join=miter] \begin{scope}[shift={($(current~page.north~west) + (\g_sdaps_edge_left_margin_dim, -\g_sdaps_edge_top_margin_dim)$)}] \draw (0,-\g_sdaps_edge_marker_length_dim) -- (0, 0) -- (\g_sdaps_edge_marker_length_dim,0); \str_if_eq:VnT \g_sdaps_style_tl { classic } { % TODO: Is the filled/non-filled mapping still correct? \int_case:nnTF \g_sdaps_page_int { { 1 } { \draw } { 2 } { \fill } { 3 } { \fill } { 4 } { \fill } { 5 } { \fill } { 6 } { \draw } } { (\g_sdaps_classic_boxpad_dim, -\g_sdaps_classic_boxpad_dim) rectangle +(\g_sdaps_classic_boxsize_dim,-\g_sdaps_classic_boxsize_dim); } { % Error out (first time) \msg_error:nn { sdapsbase } { classic_too_many_pages } } } \end{scope} \begin{scope}[shift={($(current~page.north~east) + (-\g_sdaps_edge_right_margin_dim, -\g_sdaps_edge_top_margin_dim)$)}] \draw (0,-\g_sdaps_edge_marker_length_dim) -- (0,0) -- (-\g_sdaps_edge_marker_length_dim,0); \str_if_eq:VnT \g_sdaps_style_tl { classic } { % TODO: Is the filled/non-filled mapping still correct? \int_case:nnT \g_sdaps_page_int { { 1 } { \fill } { 2 } { \fill } { 3 } { \draw } { 4 } { \draw } { 5 } { \draw } { 6 } { \draw } } { (-\g_sdaps_classic_boxpad_dim, -\g_sdaps_classic_boxpad_dim) rectangle +(-\g_sdaps_classic_boxsize_dim,-\g_sdaps_classic_boxsize_dim); } } \end{scope} \begin{scope}[shift={($(current~page.south~west) + (\g_sdaps_edge_left_margin_dim, \g_sdaps_edge_bottom_margin_dim)$)}] \draw (0,\g_sdaps_edge_marker_length_dim) -- (0, 0) -- (\g_sdaps_edge_marker_length_dim,0); \str_if_eq:VnT \g_sdaps_style_tl { classic } { % TODO: Is the filled/non-filled mapping still correct? \int_case:nnT \g_sdaps_page_int { { 1 } { \fill } { 2 } { \draw } { 3 } { \fill } { 4 } { \fill } { 5 } { \draw } { 6 } { \draw } } { (\g_sdaps_classic_boxpad_dim, \g_sdaps_classic_boxpad_dim) rectangle +(\g_sdaps_classic_boxsize_dim,\g_sdaps_classic_boxsize_dim); } } \end{scope} \begin{scope}[shift={($(current~page.south~east) + (-\g_sdaps_edge_right_margin_dim, \g_sdaps_edge_bottom_margin_dim)$)}] \draw (0,\g_sdaps_edge_marker_length_dim) -- (0mm, 0mm) -- (-\g_sdaps_edge_marker_length_dim,0); \str_if_eq:VnT \g_sdaps_style_tl { classic } { % TODO: Is the filled/non-filled mapping still correct? \int_case:nnT \g_sdaps_page_int { { 1 } { \fill } { 2 } { \draw } { 3 } { \fill } { 4 } { \draw } { 5 } { \draw } { 6 } { \fill } } { (-\g_sdaps_classic_boxpad_dim, \g_sdaps_classic_boxpad_dim) rectangle +(-\g_sdaps_classic_boxsize_dim,\g_sdaps_classic_boxsize_dim); } } \end{scope} \end{scope} %--------------------------------------------------------------------------- % barcodes/qr codes %--------------------------------------------------------------------------- \bool_if:NTF \g__sdaps_last_page_bool { \int_compare:nNnTF { \g_sdaps_page_int } = { 1 } { % if we have a one page document, just always stamp the last % page. This means that SDAPS can fall back to simplex mode % automatically. \sdaps_draw_codes: } { \bool_if:NTF \g_sdaps_twoside_bool { \int_if_odd:VT \g_sdaps_page_int { % This should no happen; draw a barcode though to keep things % somewhat sane. \msg_warning:nn { sdapsbase } { odd_page_count } \sdaps_draw_codes: } { % Even page (i.e. back) has a barcode except in "front" mode \str_if_eq:VnF \g_sdaps_twoside_barcode_tl { front } { \sdaps_draw_codes: } } } { \sdaps_draw_codes: } } % TODO: Check whether the page count is as expected? } { \bool_if:NTF \g_sdaps_twoside_bool { \str_if_eq:VnTF \g_sdaps_twoside_barcode_tl { both } { \sdaps_draw_codes: } { \str_if_eq:VnTF \g_sdaps_twoside_barcode_tl { front } { \int_if_odd:VT \g_sdaps_page_int { \sdaps_draw_codes: } } { % And back is the only thing left \int_if_odd:VF \g_sdaps_page_int { \sdaps_draw_codes: } } } } { \sdaps_draw_codes: } } %--------------------------------------------------------------------------- % watermark for non final mode %--------------------------------------------------------------------------- \bool_if:NT \g_sdaps_draft_bool { \node [rotate=60,scale=10,text~opacity=0.2,color=red] at (current~page.center) {\textsc{draft}}; } \end{tikzpicture} \group_end: } { \int_gincr:N\g_sdaps_page_int } } % \end{macrocode} % % \subsection{Starting/Ending an SDAPS context} % % These need to be used to begin rendering into an SDAPS context and finishing % everything off. % % Note that this base package does not automatically call % \textbackslash sdaps\_page\_end: for % you, so if you are using this class directly you will need to make sure that % this handler is called after all form elements on a page. An easy of doing % this is to call it from inside the page footer. % % % %\begin{macrocode} \bool_new:N \g__sdaps_last_page_bool \cs_new_protected_nopar:Nn \sdaps_begin: { \bool_gset:Nn \g__sdaps_last_page_bool \c_false_bool % TODO: We really want to make sure nobody modifies the values after \sdaps_begin: \sdaps_info_write:x{Duplex=\bool_if:NTF \g_sdaps_twoside_bool {true} {false}} \sdaps_info_write:x{PrintQuestionnaireId=\bool_if:NTF \g_sdaps_print_questionnaire_id_bool {1} {0}} \sdaps_info_write:x{ PageSize=\the\paperwidth, \the\paperheight } \sdaps_info_write:x{Style=\g_sdaps_style_tl} \sdaps_info_write:x{CheckMode=\g_sdaps_checkmode_tl} \sdaps_info_write:x{GlobalID=\g_sdaps_global_id_tl} \sdaps_info_write:x{GlobalIDLabel=\g_sdaps_global_id_label_tl} \int_gset:Nn \g_sdaps_page_int { 0 } } \cs_new_protected_nopar:Nn \sdaps_end: { % Note that using \sdaps_info_write_x:n may not work in some cases. % For this reason we write the out the Pages counter after each page, % which is fine to do. % Note that this means that the below "hack" to make onesided documents % work even in twoside (duplex) mode may not always work either. \bool_gset:Nn \g__sdaps_last_page_bool \c_true_bool } % % \end{macrocode} % % \Finale \endinput sdaps-1.9.8/tex/class/sdapsbase.ins0000644000175000000660000000354313600505201017761 0ustar benjaminlock00000000000000%% %% Copyright (C) 2015 by Benjamin Berg %% %% This work may be distributed and/or modified under the %% conditions of the LaTeX Project Public License, either version 1.3c %% of this license or (at your option) any later version. %% The latest version of this license is in %% http://www.latex-project.org/lppl.txt %% %% This work has the LPPL maintenance status `maintained'. %% %% The Current Maintainer of this work is Benjamin Berg. %% \input l3docstrip.tex \keepsilent \usedir{tex/latex/cskeleton} \preamble This is a generated file. Copyright (C) 2015 by Benjamin Berg This work may be distributed and/or modified under the conditions of the LaTeX Project Public License, either version 1.3c of this license or (at your option) any later version. The latest version of this license is in http://www.latex-project.org/lppl.txt \endpreamble \generate{\file{sdapsbase.sty}{\from{sdapsbase.dtx}{package}}} \obeyspaces \Msg{*************************************************************} \Msg{* *} \Msg{* To finish the installation you have to move the following *} \Msg{* file into a directory searched by TeX: *} \Msg{* *} \Msg{* sdapsbase.cls *} \Msg{* *} \Msg{* To produce the documentation run the file sdapsbase.dtx *} \Msg{* through LaTeX. *} \Msg{* *} \Msg{* Happy TeXing! *} \Msg{* *} \Msg{*************************************************************} \endbatchfile sdaps-1.9.8/tex/class/sdapsclassic.dtx0000644000175000000660000011176313600505201020502 0ustar benjaminlock00000000000000% \iffalse meta-comment % % Copyright (C) 2019 by Benjamin Berg % % This work may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3c % of this license or (at your option) any later version. % The latest version of this license is in % http://www.latex-project.org/lppl.txt % % This work has the LPPL maintenance status `maintained'. % % The Current Maintainer of this work is Benjamin Berg. % % \fi % % \iffalse %<*driver> \ProvidesFile{sdapsclassic.dtx} % %\NeedsTeXFormat{LaTeX2e}[1999/12/01] %\ProvidesClass{sdapsclassic} %<*class> [2015/08/02 v0.1 Initial version of SDAPS classic class] % % %<*driver> \documentclass{ltxdoc} %\EnableCrossrefs \CodelineIndex \RecordChanges \begin{document} \DocInput{sdapsclassic.dtx} \end{document} % % \fi % % \CheckSum{0} % % \CharacterTable % {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z % Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z % Digits \0\1\2\3\4\5\6\7\8\9 % Exclamation \! Double quote \" Hash (number) \# % Dollar \$ Percent \% Ampersand \& % Acute accent \' Left paren \( Right paren \) % Asterisk \* Plus \+ Comma \, % Minus \- Point \. Solidus \/ % Colon \: Semicolon \; Less than \< % Equals \= Greater than \> Question mark \? % Commercial at \@ Left bracket \[ Backslash \\ % Right bracket \] Circumflex \^ Underscore \_ % Grave accent \` Left brace \{ Vertical bar \| % Right brace \} Tilde \~} % % % \changes{v0.1}{2015/01/14}{Initial version} % % \GetFileInfo{sdapsclassic.dtx} % % \DoNotIndex{\newcommand,\newenvironment} % % % \title{The \textsf{sdapsclassic} package\thanks{This document % corresponds to \textsf{sdapsclassic}~\fileversion, dated \filedate.}} % \author{Benjamin Berg \\ \texttt{benjamin@sipsolutions.net}} % % \maketitle % % \section{Documentation} % % Please refer to \url{https://sdaps.org/class-doc} for documentation. % % \StopEventually{\PrintChanges\PrintIndex} % % \section{Implementation} % % This package uses the \LaTeX3 language internally, so we need to enable it. % \begin{macrocode} % We need at least 2011-08-23 for \keys_set_known:nnN \RequirePackage{expl3}[2011/08/23] %\RequirePackage{xparse} \ExplSyntaxOn \RequirePackage{sdapsbase} \RequirePackage{sdapslayout} % We use verbatim to grab the content of the questionnaire envorinment into a % temporary file. This way we can input it multiple times for repeating the % the content. \RequirePackage{verbatim} % \end{macrocode} % Now a lot of LaTeX 2e stuff that is basically just a copy of the old class. % Would be nicer to redo this with xparse, but what the heck. % \begin{macrocode} \RequirePackage{scrkbase} %------------------------------------------------------------------------------- % option processing %------------------------------------------------------------------------------- % Whether the main SDAPS program will be used \DeclareOption{disable_recognition}{\bool_gset_false:N\g_sdaps_recognition_bool} % Whether sdaps should print the questionnaire id \DeclareOption{no_print_questionnaire_id}{\bool_gset_false:N\g_sdaps_print_questionnaire_id_bool\seq_gset_from_clist:Nn \g_sdaps_questionnaire_ids_seq {{}}} \DeclareOption{print_questionnaire_id}{\bool_gset_true:N\g_sdaps_print_questionnaire_id_bool\seq_gset_from_clist:Nn \g_sdaps_questionnaire_ids_seq {{NONE}}} % pass unknown options to scrartcl \DeclareOption*{\PassOptionsToClass{\CurrentOption}{scrartcl}} % We need this if right now as it is set by sdaps.opt. \newif\if@sdaps@draft\@sdaps@drafttrue \DeclareOption{final}{\@sdaps@draftfalse} \tl_gset:Nn\g_sdaps_style_tl{qr}% \DefineFamily{SDAPS} \DefineFamilyMember{SDAPS} \DefineFamilyKey{SDAPS}{sdaps_style}[qr]% {% \KOMA@set@ncmdkey{sdaps_style}{@tempa}{% {code128}{0},% {custom}{1},% {qr}{2}% }{#1}% \ifcase \@tempa\relax \tl_gset:Nn\g_sdaps_style_tl{code128}% \or \tl_gset:Nn\g_sdaps_style_tl{custom}% \or \tl_gset:Nn\g_sdaps_style_tl{qr}% \fi } \DefineFamilyKey{SDAPS}{twoside_barcode}[both]% {% \KOMA@set@ncmdkey{twoside_barcode}{@tempa}{% {both}{0},% {front}{1},% {back}{2}% }{#1}% \ifcase \@tempa\relax \tl_gset:Nn\g_sdaps_twoside_barcode_tl{both}% \or \tl_gset:Nn\g_sdaps_twoside_barcode_tl{front}% \or \tl_gset:Nn\g_sdaps_twoside_barcode_tl{back}% \fi } \DefineFamilyKey{SDAPS}{checkmode}[checkcorrect]% {% \KOMA@set@ncmdkey{checkmode}{@tempa}{% {checkcorrect}{0},% {check}{1},% {fill}{2}% }{#1}% \ifcase \@tempa\relax \tl_gset:Nn\g_sdaps_checkmode_tl{checkcorrect}% \or \tl_gset:Nn\g_sdaps_checkmode_tl{check}% \or \tl_gset:Nn\g_sdaps_checkmode_tl{fill}% \fi } \DefineFamilyKey{SDAPS}{globalid}[] { \tl_gset:Nn \g_sdaps_global_id_tl { #1 } } \DefineFamilyKey{SDAPS}{globalidlabel}[] { \tl_gset:Nn \g_sdaps_global_id_label_tl { #1 } } % Set default options for scrartcl. Is this done correctly? \PassOptionsToClass{headings=small}{scrartcl} \PassOptionsToClass{twoside}{scrartcl} % Well, I don't think that this worked in the past ... %\PassOptionsToClass{10pt}{scrartcl} \seq_new:N \g_sdaps_questionnaire_ids_seq \seq_gset_from_clist:Nn \g_sdaps_questionnaire_ids_seq {{}} % process given options \FamilyProcessOptions{SDAPS}\relax %------------------------------------------------------------------------------- % load base-class %------------------------------------------------------------------------------- \LoadClass{scrartcl} %------------------------------------------------------------------------------- % required packages %------------------------------------------------------------------------------- % geometry package \RequirePackage{geometry} % Corner mark postions plus 2mm, except for the header \geometry{top=12mm} \geometry{bottom=14mm} \geometry{hmargin=12mm} \geometry{includeheadfoot} \geometry{headheight=\baselineskip} \geometry{headsep=\baselineskip} % QR code size plus 2mm \geometry{footskip=12mm} % ifthen package \RequirePackage{ifthen} % fontenc package \RequirePackage[T1]{fontenc} % color \RequirePackage{color} % Symbols (boxes) \RequirePackage{amssymb} % For writing out the page number of boxes \RequirePackage{refcount} % Defines the LastPage label \RequirePackage{lastpage} % Environment creation that gets the body as a macro \RequirePackage{environ} % headers and footers \usepackage{scrlayer-scrpage} \clearpairofpagestyles \chead*{\@title} \cfoot*{\sdapspagemark} % hyperrefs \RequirePackage{url} \RequirePackage{hyperref} \hypersetup{% breaklinks,% baseurl = http://,% pdfborder = 0 0 0,% pdfpagemode = UseNone,% pdfcreator = \LaTeX{} with `sdaps' class,% pdfproducer = \LaTeX{} } % graphics \RequirePackage{graphicx} % Section formatting \RequirePackage{sectsty} % table of fixed width \RequirePackage{tabularx} % Babel (needed for the translator) \RequirePackage{babel} % Translation \RequirePackage{translator} \usedictionary{translator-sdaps-dictionary} % Execute sdaps.opt file to allow SDAPS to override any options \InputIfFileExists{sdaps.opt}{}{} %------------------------------------------------------------------------------- % class definition %------------------------------------------------------------------------------- % minimal base settings \setlength\lineskip{1\p@} \setlength\normallineskip{1\p@} \renewcommand\baselinestretch{} \setlength{\parindent}{0pt} \setlength{\parskip}{1.0ex \@plus 1.5ex \@minus -0.25ex} %\setlength{\parskip}{0pt} \setlength\columnsep{10\p@} \setlength\columnseprule{0\p@} % Redefine the spacings for \subsection ie. \_sdaps_classic_question. \renewcommand\section{\@startsection {section}{1}{\z@}% {-\parskip}% {\parskip}% {\normalfont\Large\bfseries\SS@sectfont}} \renewcommand\subsection{ \@startsection{subsection}{2}{\z@}% {0.5\parskip}% {0.25\parskip}% These are deleted again for questions {}% } \pagestyle{scrheadings} \pagenumbering{arabic} \raggedbottom %\flushbottom \onecolumn % % Fonts for the "classic" class % %common font settings \newkomafont{questionfont}{} \newkomafont{choicefont}{} %singlemark \newkomafont{singlemarkquestionfont}{\usekomafont{questionfont}} \newkomafont{singlemarkchoicefont}{\usekomafont{choicefont}} %markgroup \newkomafont{marklinequestionfont}{\usekomafont{questionfont}} \newkomafont{marklinechoicefont}{\usekomafont{choicefont}} %choicequestion \newkomafont{choiceitemfont}{\usekomafont{choicefont}} %choicegroup \newkomafont{choicegroupchoicefont}{\usekomafont{questionfont}} \newkomafont{choicegrouplinefont}{\usekomafont{choicefont}} % \end{macrocode} % % \subsection{A bunch of old commands} % % % \begin{macrocode} \providecommand{\addinfo}[2]{ \sdaps_info_write:x{\unexpanded{#1}=\unexpanded{#2}} } \newcommand\qid{\tl_use:N \g__sdaps_questionnaire_id_tl} \def\_sdaps_classic_question#1{% \tl_if_empty:nTF{#1}{ \refstepcounter{subsection}% \par% } { % #1 is nonempty \subsection{\usekomafont{questionfont}\strut\ignorespaces#1}% % This is extra spacing after the subsection is removed. By doing this we % get exactly one \parskip \nobreak% \vspace{-0.25\parskip}% \nobreak% } } \newenvironment{info}{% \group_begin: { \par % Prevent top skip glue from being inserted at the start of the page \topskip=0pt \noindent\hrule height 1pt% \nobreak \vspace{-\parskip} \nobreak \vspace{0.5ex} \nobreak } }{% \par \nobreak \vspace{-\parskip} \nobreak \vspace{0.5ex} \nobreak \noindent\hrule height 1pt \group_end: } \definecolor{sectionbgcolor}{gray}{0.8} \definecolor{sectionfgcolor}{gray}{0.0} \newcommand{\sectbox}[1]{% \noindent\protect\colorbox{sectionbgcolor}{% \@tempdima=\hsize \advance\@tempdima by-2\fboxsep \protect\parbox{\@tempdima}{% \smallskip \raggedright % extra commands here \color{sectionfgcolor}\usekomafont{section}{#1} \smallskip }% }% } \sectionfont{\sectbox} \setkomafont{disposition}{\normalfont} \addtokomafont{section}{\bfseries\sffamily} % Not sure why we even had this ... \def\smallskip{\vspace\smallskipamount} \def\medskip{\vspace\medskipamount} \def\bigskip{\vspace\bigskipamount} \newskip\smallskipamount \smallskipamount=3pt plus 1pt minus 1pt \newskip\medskipamount \medskipamount =6pt plus 2pt minus 2pt \newskip\bigskipamount \bigskipamount =12pt plus 4pt minus 4pt \cs_generate_variant:Nn \sdaps_textbox_hstretch:nnnnn { nVVnn } \cs_generate_variant:Nn \sdaps_textbox_hstretch:nnnnn { VVVnn } \cs_generate_variant:Nn \int_set:Nn { NV } % \end{macrocode} % % \subsection{The different question environments} % % % \begin{macrocode} \bool_new:N \g__sdaps_classic_have_section \bool_gset_false:N \g__sdaps_classic_have_section \cs_new_eq:NN\_sdapsclassic_origsection\section \renewcommand{\section}[1]{ \bool_if:NT \g__sdaps_classic_have_section { \sdaps_qobject_end:n { section } } \_sdapsclassic_origsection{#1} \bool_gset_true:N \g__sdaps_classic_have_section \sdaps_qobject_begin:nnn { section }{ Head }{ #1 } } \cs_new_protected_nopar:Nn \sdaps_classic_ensure_section: { \bool_if:NF \g__sdaps_classic_have_section { % This is a bad hack to make the numbering start with zero \int_gdecr:N \g__sdaps_object_id_int \bool_gset_true:N \g__sdaps_classic_have_section \sdaps_qobject_begin:nnn { section }{ Head }{ } \sdaps_context_hook_end:n { \bool_gset_false:N \g__sdaps_classic_have_section } } } \tl_new:N \l_sdaps_classic_textbox_var_tl \tl_new:N \l_sdaps_classic_textbox_text_tl \keys_define:nn { sdapsclassic / textbox } { var .tl_set:N = \l_sdaps_classic_textbox_var_tl, text .tl_set:N = \l_sdaps_classic_textbox_text_tl, } % With star non-expanding, without start expanding \providecommand{\textbox}{\@ifstar {\bool_set_false:N \l_tmpa_bool \_sdaps_classic_textbox } {\bool_set_true:N \l_tmpa_bool \_sdaps_classic_textbox } } \providecommand{\_sdaps_classic_textbox}[3][] { \keys_set:nn { sdapsclassic / textbox } { #1 } \sdaps_classic_ensure_section: \_sdaps_classic_question{#3} \tl_if_empty:NTF \l_sdaps_classic_textbox_text_tl { \sdaps_qobject_begin:nnn { textbox } { Text } { #3 } } { \sdaps_qobject_begin:nnV { textbox } { Text } \l_sdaps_classic_textbox_text_tl } \bool_if:NTF \l_tmpa_bool { \sdaps_textbox_vhstretch:Vnn \l_sdaps_classic_textbox_var_tl { #2 } { 1 } }{ \sdaps_textbox_vhstretch:Vnn \l_sdaps_classic_textbox_var_tl { #2 } { 0 } } \sdaps_qobject_end:n { textbox } } \newcounter{markcheckboxcount} \setcounter{markcheckboxcount}{5} \tl_new:N \l_sdaps_singlemark_var_tl \int_new:N \l_sdaps_singlemark_count_int \keys_define:nn { sdaps / singlemark } { var .tl_set:N = \l_sdaps_singlemark_var_tl, % 0 is equivalent to using the markcheckboxcount counter count .int_set:N = \l_sdaps_singlemark_count_int, count .initial:n = 0, } \cs_new_protected_nopar:Nn \_sdaps_classic_dummy_checkbox_prepare:NN { \group_begin: \sdaps_context_begin_local: \sdaps_context_disable_writing: \bool_if:NT #1 { \sdaps_context_append:nn { singlechoice } { draw_check=true } \sdaps_context_append:nn { multichoice } { draw_check=true } } \bool_if:NT #2 { \sdaps_context_append:nn { singlechoice } { fill=black } \sdaps_context_append:nn { multichoice } { fill=black } } } \cs_new_protected_nopar:Nn \_sdaps_classic_dummy_checkbox_single: { \sdaps_checkbox_set_type:n { singlechoice } \sdaps_checkbox:nn { } { } \group_end: \ignorespaces } \cs_new_protected_nopar:Nn \_sdaps_classic_dummy_checkbox_multi: { \sdaps_checkbox_set_type:n { multichoice } \sdaps_checkbox:nn { } { } \group_end: \ignorespaces } \providecommand{\checkbox}{ \_sdaps_classic_dummy_checkbox_prepare:NN \c_false_bool \c_false_bool \@ifstar \_sdaps_classic_dummy_checkbox_single: \_sdaps_classic_dummy_checkbox_multi: } \providecommand{\checkedbox}{% \_sdaps_classic_dummy_checkbox_prepare:NN \c_true_bool \c_false_bool \@ifstar \_sdaps_classic_dummy_checkbox_single: \_sdaps_classic_dummy_checkbox_multi: } \providecommand{\filledbox}{% \_sdaps_classic_dummy_checkbox_prepare:NN \c_false_bool \c_true_bool \@ifstar \_sdaps_classic_dummy_checkbox_single: \_sdaps_classic_dummy_checkbox_multi: } \providecommand{\correctedbox}{% \_sdaps_classic_dummy_checkbox_prepare:NN \c_true_bool \c_true_bool \@ifstar \_sdaps_classic_dummy_checkbox_single: \_sdaps_classic_dummy_checkbox_multi: } \providecommand*{\singlemark}[4][]{% \sdaps_classic_ensure_section: \group_begin: \keys_set:nn { sdaps / singlemark } { #1 } \int_compare:nNnT { \l_sdaps_singlemark_count_int } = { 0 } { \int_set:Nn \l_sdaps_singlemark_count_int { \themarkcheckboxcount } } \_sdaps_classic_question{#2}% \sdaps_qobject_begin:nnn { singlemark } { range } { #2 } \sdaps_checkbox_set_type:n { singlechoice } \tl_if_empty:NF \l_sdaps_singlemark_var_tl { \sdaps_qobject_append_var:V \l_sdaps_singlemark_var_tl } \sdaps_range:nnn{lower}{0}{#3} \sdaps_range:nnn{upper}{\int_use:N\l_sdaps_singlemark_count_int-1}{#4} \begin{tabularx}{\linewidth}{X*{\int_use:N\l_sdaps_singlemark_count_int}{c}X} {\hfill\usekomafont{singlemarkchoicefont}\strut\ignorespaces#3} & \int_step_inline:nnnn { 1 } { 1 } { \int_use:N\l_sdaps_singlemark_count_int } { \sdaps_checkbox:nn { _ ##1 } { ##1 } & } {\usekomafont{singlemarkchoicefont}#4\hfill}\\% \end{tabularx}% \sdaps_qobject_end:n { singlemark } \group_end: } \providecommand*{\singlemarkother}[5][]{% \sdaps_classic_ensure_section: \group_begin: \keys_set:nn { sdaps / singlemark } { #1 } \int_compare:nNnT { \l_sdaps_singlemark_count_int } = { 0 } { \int_set:Nn \l_sdaps_singlemark_count_int { \themarkcheckboxcount } } \_sdaps_classic_question{#2}% \sdaps_qobject_begin:nnn { singlemark } { range } { #2 } \sdaps_checkbox_set_type:n { singlechoice } \tl_if_empty:NF \l_sdaps_singlemark_var_tl { \sdaps_qobject_append_var:V \l_sdaps_singlemark_var_tl } \sdaps_range:nnn{lower}{0}{#3} \sdaps_range:nnn{upper}{\int_use:N\l_sdaps_singlemark_count_int-1}{#4} \sdaps_answer:n{#5} \begin{tabularx}{\linewidth}{X*{\int_use:N\l_sdaps_singlemark_count_int}{c}XX} {\hfill\usekomafont{singlemarkchoicefont}\strut\ignorespaces#3} & \int_step_inline:nnnn { 1 } { 1 } { \int_use:N\l_sdaps_singlemark_count_int } { \sdaps_checkbox:nn { _ ##1 } { ##1 } & } {\usekomafont{singlemarkchoicefont}#4} & {\usekomafont{singlemarkchoicefont}\sdaps_checkbox:nn { _0 } { 0 } {} ~ #5\hfill}\\% \end{tabularx}% \sdaps_qobject_end:n { singlemark } \group_end: } \dim_new:N \l__sdaps_classic_choiceitem_pad_dim \int_new:N \l__sdaps_classic_choiceitem_cols_int \int_new:N \l__sdaps_classic_choiceitem_col_int \dim_new:N \l__sdaps_classic_choicequestion_prevdepth_dim \coffin_new:N \l__sdaps_classic_choicequestion_coffin \msg_new:nnn { sdapsclassic } { choicequestion_wrong_mode } { Mode~should~always~be~vertical~inside~a~choicequestion.\\ This~likely~means~that~the~choicequestion~contains~content~other~than~one~of~the~permissable~macros. } \msg_new:nnn { sdapsclassic } { choicequestion_no_text } { Textboxes~cannot~be~used~in~singlechoice~questions.\\ It~is~currently~not~supported~to~use~text~answers~in~single~choice~questions.~Until~support~is~added~ you~can~get~similar~results~by~temporarily~changing~the~checkbox~style. } \msg_new:nnn { sdapsclassic } { choicequestion_unknown_key } { The~key~'#1'~is~unknown.\\If~you~are~migrating~from~the~old~class~then~you~need~to~add~'cols='~to~specify~the~number~of~columns. } \tl_new:N \l_sdaps_choicquestion_type_tl \tl_new:N \l_sdaps_choicequestion_var_tl \tl_new:N \l_sdaps_choicequestion_text_tl \int_new:N \l_sdaps_choicequestion_cols_int \keys_define:nn { sdaps / choicequestion } { var .tl_set:N = \l_sdaps_choicequestion_var_tl, text .tl_set:N = \l_sdaps_choicequestion_text_tl, colsep .dim_set:N = \l_sdaps_choicequestion_colsep_dim, colsep .initial:n = 6pt, rowsep .dim_set:N = \l_sdaps_choicequestion_rowsep_dim, rowsep .initial:n = 0pt, cols .int_set:N = \l_sdaps_choicequestion_cols_int, cols .initial:n = 3, type .choices:nn = { multichoice, singlechoice } { \tl_set:Nx \l_sdaps_choicquestion_type_tl { \l_keys_choice_tl } }, type .initial:n = { multichoice }, singlechoice .meta:n = { type=singlechoice }, multichoice .meta:n = { type=multichoice }, unknown .code:n = \msg_error:nnV { sdapsclassic } { choicequestion_unknown_key } \l_keys_key_tl } \tl_new:N \l_sdaps_choicequestion_choice_var_tl \tl_new:N \l_sdaps_choicequestion_choice_val_tl \tl_new:N \l_sdaps_choicequestion_choice_text_tl \keys_define:nn { sdaps / choicequestion / choice } { var .tl_set:N = \l_sdaps_choicequestion_choice_var_tl, val .tl_set:N = \l_sdaps_choicequestion_choice_val_tl, text .tl_set:N = \l_sdaps_choicequestion_choice_text_tl, } \newenvironment{choicequestion}[2][]{ \group_begin: \sdaps_classic_ensure_section: \tl_clear:N \l_sdaps_choicequestion_var_tl \tl_clear:N \l_sdaps_choicequestion_text_tl \keys_set:nn { sdaps / choicequestion } { #1 } \_sdaps_classic_question{#2}% % Setup the context \tl_if_eq:VnTF \l_sdaps_choicquestion_type_tl { multichoice } { \tl_set:Nn \l_tmpa_tl { Choice } } { \tl_set:Nn \l_tmpa_tl { Option } } \tl_if_empty:NTF \l_sdaps_choicequestion_text_tl { \sdaps_qobject_begin:nVn { choicequestion } \l_tmpa_tl { #2 } } { \sdaps_qobject_begin:nVV { choicequestion } \l_tmpa_tl \l_sdaps_choicequestion_text_tl } \sdaps_checkbox_set_type:V \l_sdaps_choicquestion_type_tl \tl_if_empty:NF \l_sdaps_choicequestion_var_tl { \sdaps_qobject_append_var:V \l_sdaps_choicequestion_var_tl } \dim_set:Nn \l__sdaps_classic_choiceitem_pad_dim { 1ex } \int_set:NV \l__sdaps_classic_choiceitem_cols_int \l_sdaps_choicequestion_cols_int \int_set:Nn \l__sdaps_classic_choiceitem_col_int { 0 } \dim_set:Nn \l__sdaps_classic_choicequestion_prevdepth_dim { 1000pt } \coffin_clear:N \l__sdaps_classic_choicequestion_coffin % We have to be in vertical mode at this point. \if_mode_vertical: % Nothing \else: \msg_error:nn { sdapsclassic } { choicequestion_wrong_mode } \fi: % It is important to look like a paragraph, otherwise latex thinks there is % nothing between the two question sections and doesn't insert a voluntary % page break. \the\everypar % Paragraph like spacing \vspace{\parskip} \def\choicequestion_clubpenalty{\penalty\clubpenalty\def\choicequestion_clubpenalty{\relax}\def\choicequestion_clubpenalty{\penalty\widowpenalty}} \def\choicequestion_widowpenalty{} }{ \if_mode_vertical: % Nothing \else: \msg_error:nn { sdapsclassic } { choicequestion_wrong_mode } \fi: \choicequestion_widowpenalty \vbox:n { \skip_horizontal:N \@totalleftmargin \box_use:N \l__sdaps_classic_choicequestion_coffin } \prevdepth=\l__sdaps_classic_choicequestion_prevdepth_dim \coffin_clear:N \l__sdaps_classic_choicequestion_coffin \sdaps_qobject_end:n { choicequestion } \group_end: \vspace{\parskip} } \newenvironment{optionquestion}[2][]{ \choicequestion[singlechoice,#1]{#2} } { \endchoicequestion } \cs_new_protected_nopar:Nn \_sdaps_classic_line_shipout_add:NNn { % We have to be in vertical mode at this point. \if_mode_vertical: % Nothing \else: \msg_error:nn { sdapsclassic } { choicequestion_wrong_mode } \fi: % Is linewidth the right thing here? \int_compare:nT { \l__sdaps_classic_choiceitem_col_int + #3 > \l__sdaps_classic_choiceitem_cols_int } { % We can only typeset a coffin in vertical mode if we use the box function \vbox:n { \skip_horizontal:N \@totalleftmargin \box_use:N \l__sdaps_classic_choicequestion_coffin } \prevdepth=\l__sdaps_classic_choicequestion_prevdepth_dim \skip_vertical:N \l_sdaps_choicequestion_rowsep_dim \coffin_clear:N \l__sdaps_classic_choicequestion_coffin \dim_set:Nn \l__sdaps_classic_choicequestion_prevdepth_dim { 1000pt } \choicequestion_clubpenalty \int_set:Nn \l__sdaps_classic_choiceitem_col_int { 0 } } \dim_set:Nn \l_tmpa_dim { \linewidth / \l__sdaps_classic_choiceitem_cols_int + \l__sdaps_classic_choiceitem_pad_dim / \l__sdaps_classic_choiceitem_cols_int } \dim_set:Nn \l_tmpa_dim { \l__sdaps_classic_choiceitem_col_int \l_tmpa_dim } \dim_compare:nNnTF { \coffin_dp:N \l__sdaps_classic_choicequestion_coffin } > { \coffin_dp:N #1 } { \dim_set:Nn \l__sdaps_classic_choicequestion_prevdepth_dim {\dim_min:nn { \l__sdaps_classic_choicequestion_prevdepth_dim } { #2 + \coffin_dp:N \l__sdaps_classic_choicequestion_coffin - \coffin_dp:N #1 } } } { \dim_set:Nn \l__sdaps_classic_choicequestion_prevdepth_dim {\dim_min:nn { \l__sdaps_classic_choicequestion_prevdepth_dim + \coffin_dp:N #1 - \coffin_dp:N \l__sdaps_classic_choicequestion_coffin } { #2 } } } \coffin_join:NnnNnnnn \l__sdaps_classic_choicequestion_coffin { l } { H } #1 { l } { H } { \l_tmpa_dim } { 0pt } \int_add:Nn \l__sdaps_classic_choiceitem_col_int { #3 } } \providecommand*{\choiceitem}[2][]{% \tl_clear:N \l_sdaps_choicequestion_choice_var_tl \tl_clear:N \l_sdaps_choicequestion_choice_val_tl \tl_clear:N \l_sdaps_choicequestion_choice_text_tl \keys_set:nn { sdaps / choicequestion / choice } { #1 } \tl_if_empty:NTF \l_sdaps_choicequestion_choice_text_tl { \sdaps_answer:n { #2 } } { \sdaps_answer:V \l_sdaps_choicequestion_choice_text_tl } \dim_set:Nn \l_tmpa_dim { \linewidth / \l__sdaps_classic_choiceitem_cols_int - \l__sdaps_classic_choiceitem_pad_dim + \l__sdaps_classic_choiceitem_pad_dim / \l__sdaps_classic_choiceitem_cols_int } \hcoffin_set:Nn \l_tmpa_coffin { \hbox_set:Nn \l_tmpa_box { \strut \sdaps_checkbox:VV \l_sdaps_choicequestion_choice_var_tl \l_sdaps_choicequestion_choice_val_tl {}\ } \dim_set:Nn \l_tmpb_dim { \box_wd:N \l_tmpa_box } \hskip \l_sdaps_choicequestion_colsep_dim \hbox_unpack:N \l_tmpa_box \begin{minipage}[t]{\dim_eval:n { \l_tmpa_dim - \l_tmpb_dim - 2\l_sdaps_choicequestion_colsep_dim}} \noindent \usekomafont{choiceitemfont} \tl_trim_spaces:n { #2 }\strut \par \dim_gset:Nn \g_tmpa_dim { \dim_max:nn { \box_dp:N \l_tmpa_box } { \prevdepth } } \unskip \end{minipage} } \_sdaps_classic_line_shipout_add:NNn \l_tmpa_coffin \g_tmpa_dim { 1 } \ignorespaces } \providecommand*{\choicemulticolitem}[3][]{ % \tl_clear:N \l_sdaps_choicequestion_choice_var_tl \tl_clear:N \l_sdaps_choicequestion_choice_val_tl \tl_clear:N \l_sdaps_choicequestion_choice_text_tl \keys_set:nn { sdaps / choicequestion / choice } { #1 } \tl_if_empty:NTF \l_sdaps_choicequestion_choice_text_tl { \sdaps_answer:n { #3 } } { \sdaps_answer:V \l_sdaps_choicequestion_choice_text_tl } \dim_set:Nn \l_tmpa_dim { #2\linewidth / \l__sdaps_classic_choiceitem_cols_int - \l__sdaps_classic_choiceitem_pad_dim + #2 \l__sdaps_classic_choiceitem_pad_dim / \l__sdaps_classic_choiceitem_cols_int } \hcoffin_set:Nn \l_tmpa_coffin { \hbox_set:Nn \l_tmpa_box { \strut \sdaps_checkbox:VV \l_sdaps_choicequestion_choice_var_tl \l_sdaps_choicequestion_choice_val_tl {}\ } \dim_set:Nn \l_tmpb_dim { \box_wd:N \l_tmpa_box } \hskip \l_sdaps_choicequestion_colsep_dim \hbox_unpack:N \l_tmpa_box \begin{minipage}[t]{\dim_eval:n { \l_tmpa_dim - \l_tmpb_dim - 2\l_sdaps_choicequestion_colsep_dim}} \noindent \usekomafont{choiceitemfont} \tl_trim_spaces:n { #3 }\strut \par \dim_gset:Nn \g_tmpa_dim { \dim_max:nn { \box_dp:N \l_tmpa_box } { \prevdepth } } \unskip \end{minipage} } \_sdaps_classic_line_shipout_add:NNn \l_tmpa_coffin \g_tmpa_dim { #2 } \ignorespaces } \providecommand{\choiceitemtext}[4][]{% \tl_clear:N \l_sdaps_choicequestion_choice_var_tl \tl_clear:N \l_sdaps_choicequestion_choice_val_tl \tl_clear:N \l_sdaps_choicequestion_choice_text_tl \keys_set:nn { sdaps / choicequestion / choice } { #1 } % TODO: Warn if val has been set here % If not multichoice then warn \tl_if_eq:VnF \l_sdaps_choicquestion_type_tl { multichoice } { \msg_error:nn { sdapsclassic } { choicequestion_no_text } } \tl_if_empty:NTF \l_sdaps_choicequestion_choice_text_tl { \sdaps_answer:n { #4 } } { \sdaps_answer:V \l_sdaps_choicequestion_choice_text_tl } \dim_set:Nn \l_tmpa_dim { #3\linewidth / \l__sdaps_classic_choiceitem_cols_int - \l__sdaps_classic_choiceitem_pad_dim + #3 \l__sdaps_classic_choiceitem_pad_dim / \l__sdaps_classic_choiceitem_cols_int } \hcoffin_set:Nn \l_tmpa_coffin { \hskip \l_sdaps_choicequestion_colsep_dim \begin{minipage}[t]{\dim_eval:n { \l_tmpa_dim - 2\l_sdaps_choicequestion_colsep_dim}} \usekomafont{choiceitemfont} \dim_set:Nn \l_tmpa_dim { #2 } \dim_set:Nn \l_tmpb_dim { #2 } \dim_set:Nn \l_tmpa_dim { 0.5 \l_tmpa_dim - 0.8ex } \dim_set:Nn \l_tmpb_dim { 0.5 \l_tmpb_dim + 0.8ex } \strut\ignorespaces \tl_trim_spaces:n { #4 } ~ \sdaps_textbox_hstretch:VVVnn \l_sdaps_choicequestion_choice_var_tl \l_tmpa_dim \l_tmpb_dim { 0pt } { 1 } \par \dim_gset:Nn \g_tmpa_dim { \prevdepth } \unskip \end{minipage} } \_sdaps_classic_line_shipout_add:NNn \l_tmpa_coffin \g_tmpa_dim { #3 } \ignorespaces } % \end{macrocode} % % \subsection{The questionnaire environment} % % There is a bit of magic here. If (and only if) we need to render multiple % pages of the questionnaire, then we write the whole questionnaire into a % temporary file. This way we can input the file multiple times, which means % that environments changing the parser (e.g. verbatim) work properly. % % \begin{macrocode} % \iow_new:N \l__sdaps_questionnaire_iow \bool_new:N \l__sdaps_questionnaire_parse_direct_bool \bool_new:N \l__sdaps_questionnaire_info_bool \keys_define:nn { sdaps / questionnaire } { info .bool_set:N = \l__sdaps_questionnaire_info_bool, info .default:n = true, info .initial:n = true, noinfo .meta:n = { info=false }, } \cs_new_protected_nopar:Nn \_sdaps_classic_show_info: { \bool_if:NT \l__sdaps_questionnaire_info_bool { \begin{info} \translate{infotext} \\[1ex] \tl_if_eq:VnTF \g_sdaps_checkmode_tl { checkcorrect } { \begin{tabularx}{\textwidth}{lXllll} \checkbox & \strut \translate{info-multi} & \hspace{2em} \checkedbox {} & \translate{info-cross} & \hspace{1em} \correctedbox {} & \translate{info-corrected} \\ \checkbox* & \strut \translate{info-single} & \hspace{2em} \checkedbox* {} & \translate{info-cross} & \hspace{1em} \correctedbox* {} & \translate{info-corrected} \\ \end{tabularx} } { \tl_if_eq:VnTF \g_sdaps_checkmode_tl { check } { \begin{tabularx}{\textwidth}{lXll} \checkbox & \strut \translate{info-multi} & \hspace{2em} \checkedbox {} & \translate{info-cross} \\ \checkbox* & \strut \translate{info-single} & \hspace{2em} \checkedbox* {} & \translate{info-cross} \\ \end{tabularx} } { \tl_if_eq:VnTF \g_sdaps_checkmode_tl { fill } { \begin{tabularx}{\textwidth}{lXll} \checkbox & \strut \translate{info-multi} & \hspace{2em} \filledbox {} & \translate{info-fill} \\ \checkbox* & \strut \translate{info-single} & \hspace{2em} \filledbox* {} & \translate{info-fill} \\ \end{tabularx} } { \PackageError{sdaps}{Sorry, there is no help text for the checkmode you have choosen right now! Please pass the noinfo optional argument to the questionnaire environment!}\@ehb % } } } \end{info} } \ignorespaces } \newenvironment { questionnaire } [ 1 ] [] { \keys_set:nn { sdaps / questionnaire } { #1 } \hypersetup{ pdfauthor = \@author, pdftitle = \@title, pdfsubject = sdaps questionnaire \@title, pdfkeywords = sdaps questionnaire \@title } % If we only have one questionnaire ID, then parse the environment directly, % otherwise write it into a temporary file and input it multiple times. \group_begin: \if@twoside \bool_gset_true:N \g_sdaps_twoside_bool \else \bool_gset_false:N \g_sdaps_twoside_bool \fi % Enable all metadata writing by default \sdaps_context_enable_writing: \sdaps_info_write:x{Author=\exp_not:o{\@author}} \sdaps_info_write:x{Title=\exp_not:o{\@title}} \int_compare:nTF { \seq_count:N \g_sdaps_questionnaire_ids_seq <= 1 } { \bool_set_true:N \l__sdaps_questionnaire_parse_direct_bool % Set the questionnaire ID \seq_gpop_left:NN \g_sdaps_questionnaire_ids_seq \l_tmpa_tl \sdaps_set_questionnaire_id:V \l_tmpa_tl % And, begin the questionnaire \sdaps_begin: \_sdaps_classic_show_info: } { \bool_set_false:N \l__sdaps_questionnaire_parse_direct_bool % Write content into a file, see "verbatim" documentation for more information. % TODO: Allow multiple temporary files by postfixing with integer? \iow_open:Nn \l__sdaps_questionnaire_iow { \c_sys_jobname_str . questionnaire } \cs_set_eq:NN\do\@makeother\dospecials \catcode`\^^M\active \def\verbatim@processline{ \iow_now:Nx \l__sdaps_questionnaire_iow {\the\verbatim@line} } \verbatim@ } } { \bool_if:NTF \l__sdaps_questionnaire_parse_direct_bool { % Just end everything, nothing else to do. % Make sure we always end the current paragraph. \par \sdaps_end: \group_end: } { % We are done inputting the questionnaire \iow_close:N \l__sdaps_questionnaire_iow \group_end: % Now cycle through all IDS and output it again. \group_begin: \seq_map_inline:Nn \g_sdaps_questionnaire_ids_seq { \sdaps_set_questionnaire_id:n { ##1 } % Reset a lot of global LaTeX counters \@ifundefined{c@page}{}{\setcounter{page}{1}} \@ifundefined{c@part}{}{\setcounter{part}{0}} \@ifundefined{c@chapter}{}{\setcounter{chapter}{0}} \@ifundefined{c@paragraph}{}{\setcounter{paragraph}{0}} \@ifundefined{c@subparagraph}{}{\setcounter{subparagraph}{0}} \@ifundefined{c@section}{}{\setcounter{section}{0}} \@ifundefined{c@subsection}{}{\setcounter{subsection}{0}} \@ifundefined{c@subsubsection}{}{\setcounter{subsubsection}{0}} \@ifundefined{c@equation}{}{\setcounter{equation}{0}} \@ifundefined{c@figure}{}{\setcounter{figure}{0}} \@ifundefined{c@table}{}{\setcounter{table}{0}} \sdaps_begin: \_sdaps_classic_show_info: \input{ \c_sys_jobname_str . questionnaire } % Make sure we always end the current paragraph. \par \sdaps_end: \newpage % Close the output file now (after the page has been shipped out) % XXX: This is a bit of a hack, as disabling metadata writing has side effects \iow_close:N \g_sdaps_infofile_iow } \group_end: } } \def\sdapspagemark{ \sdaps_page_end: } % \end{macrocode} % % \subsection{The group environments} % % Alias for the group environments. % % \begin{macrocode} % \tl_new:N \l__sdaps_classic_group_var_tl \tl_new:N \l__sdaps_classic_group_text_tl \tl_new:N \l__sdaps_classic_group_extra_tl \keys_define:nn { sdapsclassic / group } { var .tl_set:N = \l__sdaps_classic_group_var_tl, text .tl_set:N = \l__sdaps_classic_group_text_tl, } \newenvironment { choicegroup } [ 2 ] [] { \group_begin: \keys_set_known:nnN { sdapsclassic / group } { #1 } \l__sdaps_classic_group_extra_tl \_sdaps_classic_question{#2} \tl_if_empty:NTF \l__sdaps_classic_group_text_tl { \sdaps_qobject_begin:nnn { choicegroup } { Head } { #2 } } { \sdaps_qobject_begin:nnV { choicegroup } { Head } \l__sdaps_classic_group_text_tl } \tl_if_empty:NF \l__sdaps_classic_group_var_tl { \sdaps_qobject_append_var:V \l__sdaps_classic_group_var_tl } % Undefine the question (and choice) commands in local scope so that they % can be redefined by choicearray without any issues. % Note that \cs_undefine:N works in global scope, so we cannot use it here. \cs_set_eq:NN\question\tex_undefined:D \cs_set_eq:NN\choice\tex_undefined:D \expandafter\choicearray\expandafter[\l__sdaps_classic_group_extra_tl] % XXX: This is a bit of a hack, set in global scope because the choicearray % environment does evil things with scopes. \cs_gset_eq:NN\groupaddchoice\choice \cs_gset_eq:NN\choiceline\question } { \cs_gset_eq:NN\groupaddchoice\undefined \cs_gset_eq:NN\choiceline\undefined \endchoicearray \sdaps_qobject_end:n { choicegroup } \group_end: } \newenvironment { optiongroup } [ 2 ] [] { \group_begin: \keys_set_known:nnN { sdapsclassic / group } { #1 } \l__sdaps_classic_group_extra_tl \_sdaps_classic_question{#2} \tl_if_empty:NTF \l__sdaps_classic_group_text_tl { \sdaps_qobject_begin:nnn { optiongroup } { Head } { #2 } } { \sdaps_qobject_begin:nnV { optiongroup } { Head } \l__sdaps_classic_group_text_tl } \tl_if_empty:NF \l__sdaps_classic_group_var_tl { \sdaps_qobject_append_var:V \l__sdaps_classic_group_var_tl } % Undefine the question (and choice) commands in local scope so that they % can be redefined by optionarray without any issues. % Note that \cs_undefine:N works in global scope, so we cannot use it here. \cs_set_eq:NN\question\tex_undefined:D \cs_set_eq:NN\choice\tex_undefined:D \expandafter\optionarray\expandafter[\l__sdaps_classic_group_extra_tl] % XXX: This is a bit of a hack, set in global scope because the optionarray % environment does evil things with scopes. \cs_gset_eq:NN\groupaddchoice\choice \cs_gset_eq:NN\optionline\question } { \cs_gset_eq:NN\groupaddoption\undefined \cs_gset_eq:NN\optionline\undefined \endoptionarray \sdaps_qobject_end:n { optiongroup } \group_end: } \newenvironment { markgroup } [ 2 ] [] { \group_begin: \keys_set_known:nnN { sdapsclassic / group } { #1 } \l__sdaps_classic_group_extra_tl \_sdaps_classic_question{#2} \tl_if_empty:NTF \l__sdaps_classic_group_text_tl { \sdaps_qobject_begin:nnn { markgroup } { Head } { #2 } } { \sdaps_qobject_begin:nnV { markgroup } { Head } \l__sdaps_classic_group_text_tl } \tl_if_empty:NF \l__sdaps_classic_group_var_tl { \sdaps_qobject_append_var:V \l__sdaps_classic_group_var_tl } % Undefine the range command in local scope so that it can be redefined % by rangearray without any issues. % Note that \cs_undefine:N works in global scope, so we cannot use it here. \cs_set_eq:NN\range\tex_undefined:D \expandafter\rangearray\expandafter[\l__sdaps_classic_group_extra_tl] % XXX: This is a bit of a hack, set in global scope because the choicearray % environment does evil things with scopes. \cs_gset_eq:NN\markline\range } { \cs_gset_eq:NN\markline\undefined \endrangearray \sdaps_qobject_end:n { markgroup } \group_end: } \ExplSyntaxOff % \end{macrocode} % \Finale \endinput sdaps-1.9.8/tex/class/sdapsclassic.ins0000644000175000000660000000354713600505201020474 0ustar benjaminlock00000000000000%% %% Copyright (C) 2015 by Benjamin Berg %% %% This work may be distributed and/or modified under the %% conditions of the LaTeX Project Public License, either version 1.3c %% of this license or (at your option) any later version. %% The latest version of this license is in %% http://www.latex-project.org/lppl.txt %% %% This work has the LPPL maintenance status `maintained'. %% %% The Current Maintainer of this work is Benjamin Berg. %% \input l3docstrip.tex \keepsilent \usedir{tex/latex/cskeleton} \preamble This is a generated file. Copyright (C) 2015 by Benjamin Berg This work may be distributed and/or modified under the conditions of the LaTeX Project Public License, either version 1.3c of this license or (at your option) any later version. The latest version of this license is in http://www.latex-project.org/lppl.txt \endpreamble \generate{\file{sdapsclassic.cls}{\from{sdapsclassic.dtx}{class}}} \obeyspaces \Msg{*************************************************************} \Msg{* *} \Msg{* To finish the installation you have to move the following *} \Msg{* file into a directory searched by TeX: *} \Msg{* *} \Msg{* sdapsclassic.cls *} \Msg{* *} \Msg{* To produce the documentation run the file sdapsclassic.dtx*} \Msg{* through LaTeX. *} \Msg{* *} \Msg{* Happy TeXing! *} \Msg{* *} \Msg{*************************************************************} \endbatchfile sdaps-1.9.8/tex/class/sdapscode128.tex0000644000175000000660000004255213600505201020226 0ustar benjaminlock00000000000000%% Copyright 1996 Petr Olsak. % % This work may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3c % of this license or (at your option) any later version. % The latest version of this license is in % http://www.latex-project.org/lppl.txt % % The work has been licensed under these terms with permission % by Petr Olsak for distribution with SDAPS. % % The original file follows % See http://math.feld.cvut.cz/olsak/ % Macro for conversion of string to barcodes by Code 128 standard %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % March 1996 (C) Petr Ol\v{s}\'ak % For user information see the file test128.tex % Comments at programmer level are included in this file. First you can % read the end of this file: The description of Code 128 standard. \wlog{**** Macro for barcodes in "Code 128" by (C) Petr Olsak used ****} % Declarations: \newdimen\X % the module size X, \newdimen\bcorr % the bar correction (see bellow). \newdimen\workdimen \newdimen\barheight % internal variables \newtoks\inputtext \newtoks\icode \newcount\tempnum \newcount\chnum \newcount\chtotal \newif\ifnext \newif\ifchar \def\empty{} \def\End{@@end} % Implicit values: \X=.33mm % The X module width. \bcorr=.020mm % Bar reduction. \barheight=1.5cm % The code height. % First we declare some tables. % "\definetable string \relax": Each token from "string" gets a value % (spaces are ignored). First token gets value , second % and so on. It is possible to reconstruct the value by % "\csname\string\endcsname". \def\definetable#1#2 {\tempnum=#2 \def\temp{#1}\let\next=\repeatdefine \next} \def\repeatdefine#1{\ifx#1\relax \let\next=\relax \else \expandafter\edef\csname\temp\string#1\endcsname{\the\tempnum}% \advance\tempnum by1 \fi \next} %%%%%%%%%%%%%%%%%%%%% Basic tables for Code 128: %%%%%%%%%%%%%%%%%%%%%%%%%%% \definetable:0 % All input characters from Code B: \ ! " \# \$ \% \& ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \\ ] \^ \_ ` a b c d e f g h i j k l m n o p q r s t u v w x y z \{ | \} \~ \DEL \relax \definetable:64 % Other input characters from Code A: \NUL \SOH \STX \ETX \EOT \ENQ \ACK \BEL \BS \HT \LF \VT \FF \CR \SO \SI \DLE \DCone \DCtwo \DCthree \DCfour \NAK \SYN \ETB \CAN \EM \SUB \ESC \FS \GS \RS \US \relax \definetable:0 \ \relax % the \^^M must be the same as \ \definetable:0 \SP \relax % the \SP is alternative to \ \definetable{D:}0 0123456789 \relax % Digits \definetable{B:}0 `abcdefghijklmnopqrstuvwxyz\{\|\}\~ \relax % Only in Code B \definetable{A:}0 \NUL \SOH \STX \ETX \EOT \ENQ \ACK \BEL \BS \HT \LF \VT \FF \CR \SO \SI \DLE \DCone \DCtwo \DCthree \DCfour \NAK \SYN \ETB \CAN \EM \SUB \ESC \FS \GS \RS \US \relax % only in code A. \def\tableofcode#1{\ifcase#1 % The output characters: 212222\or 222122\or 222221\or 121223\or 121322\or % 0-4 131222\or 122213\or 122312\or 132212\or 221213\or % 5-9 221312\or 231212\or 112232\or 122132\or 122231\or % 10-14 113222\or 123122\or 123221\or 223211\or 221132\or % 15-19 221231\or 213212\or 223112\or 312131\or 311222\or % 20-24 321122\or 321221\or 312212\or 322112\or 322211\or % 25-29 212123\or 212321\or 232121\or 111323\or 131123\or % 30-34 131321\or 112313\or 132113\or 132311\or 211313\or % 35-39 231113\or 231311\or 112133\or 112331\or 132131\or % 40-44 113123\or 113321\or 133121\or 313121\or 211331\or % 45-49 231131\or 213113\or 213311\or 213131\or 311123\or % 50-54 311321\or 331121\or 312113\or 312311\or 332111\or % 55-59 314111\or 221411\or 431111\or 111224\or 111422\or % 60-64 121124\or 121421\or 141122\or 141221\or 112214\or % 65-69 112412\or 122114\or 122411\or 142112\or 142211\or % 70-74 241211\or 221114\or 413111\or 241112\or 134111\or % 75-79 111242\or 121142\or 121241\or 114212\or 124112\or % 80-84 124211\or 411212\or 421112\or 421211\or 212141\or % 85-89 214121\or 412121\or 111143\or 111341\or 131141\or % 90-94 114113\or 114311\or 411113\or 411311\or 113141\or % 95-99 114131\or 311141\or 411131\else 00000\fi } % 100-102 \def\startA{211412} \def\startB{211214} \def\startC{211232} \def\stop{23311120} % Implementations of tests: % After "\testchar " the "\ifchar" has following meaning: % true, if is in digits, only in A or only in B respectively with % is {D:}, {A:} or {B:}. \def\testchar #1#2{\expandafter\ifx\csname#1\string#2\endcsname \relax \charfalse \else \chartrue \fi} % After "\numofdigits string\stop" is used, the \tempnum register contain % the number of digits from first continuosly group of digits from left in % "string". If "string" starts with no digit then \tempnum=0. \def\numofdigits{\tempnum=0 \let\next=\cyklnumber \cyklnumber} \def\cyklnumber#1{\testchar {D:}#1% \ifchar \advance\tempnum by1 \else \ifx #1\stop\def\next{}% \else \def\next##1\stop{}\fi \fi \next} % After "\testnext string\stop" is used, the "\ifnext" has % the following meaning: % 1. is {A:}: "\ifnext" is true, if first character from "string" is % only in A code after skip all common characters shared in codeA and B. % 2. is {B:}: "\ifnext" is true, if first character from "string" is % only in B code after skip all common characters shared in codeA and B. \def\testA{A:} \def\testnext#1{\nextfalse \def\tempA{#1}% \ifx\tempA\testA \def\tempB{B:}\else \def\tempB{A:}\fi \let\next=\cyklcontrol \next} \def\cyklcontrol#1{% \ifx#1\stop \let\next=\relax \else \testchar \tempB #1% \ifchar \def\next##1\stop{}% \else \testchar \tempA #1% \ifchar \nexttrue \def\next##1\stop{}\fi \fi \fi \next} % "\addtok \cs" adds the "\cs," into \icode. % "\addtoks{string} adds the "string," into \icode. "string" is the number % of line in table 1, so we re-calculate the current check sum. % "\addchar adds the numerical value of (declared in % \definetable:) into \icode. This value is followed by comma too. \def\addtok#1{\edef\act{\noexpand\icode={\the\icode\noexpand#1,}}\act} \def\addtoks#1{\edef\act{\noexpand\icode={\the\icode#1,}}\act \tempnum=#1 \multiply\tempnum by\chnum \advance\chtotal by\tempnum \advance\chnum by 1\relax} \def\addchar#1{\expandafter\ifx\csname:\string#1\endcsname\relax \errmessage{The input token "\string#1" is not included in Code 128 table, will ignored}% \else \expandafter\addtoks\expandafter{\csname:\string#1\endcsname}\fi} % \code{text} first converts the input text into internal representation in % \icode. The format of \icode is: "\start,num,num,num,\stop,", where % "\start" is one of "\startA" or "\startB" or "\startC". The % represents the line of code table (see standard of Code 128 bellow) % of output characters. The amount of s is not restricted. The sequence % is terminated by "\stop,". See to .log for example of this format. % % The choice of the start character: % If next 4 input characters are digits then \startC % else if the next uncommon char is from code A and not from B then \startA % else \startB % The "next uncommon char" is first character from left which falls % into code A xor code B \def\code#1{\inputtext={#1}\wlog{** Code 128 ** input: \the\inputtext}% \icode={}\chnum=1 \numofdigits#1\stop % in \tempnum is the number of digits now \ifnum\tempnum>3 \addtok\startC \chtotal=2 \let\Next=\codeC \else \testnext{A:} #1\stop \ifnext \addtok\startA \chtotal=0 \let\Next=\codeA \else \addtok\startB \chtotal=1 \let\Next=\codeB \fi \fi \Next #1\End\End} % There is mode A. Test to change the mode: % If the next 4 input characters are digits and the number of digits are even % then switch to modeC using . % If the next char is from Code B and not from Code A then: % if the next uncommnon char is from Code B and not from A then % switch to mode B using . % else include and stay in mode A. \def\codeA #1#2#3\End{\addchar#1% \numofdigits#2#3\stop \ifnum\tempnum>3 \ifodd\tempnum\else \addtoks{99}\let\Next=\codeC \fi \else \ifx#2\End \let\Next=\finalcode \else \testchar{B:} #2% \ifchar \testnext{B:} #3\stop \ifnext \addtoks{100}\let\Next=\codeB \else \addtoks{98}\fi \fi \fi \fi \Next #2#3\End} % There is mode B. Test to change the mode: % If the next 4 input characters are digits and the number of digits are even % then switch to modeC using % If the next char is from Code A and not from Code B then: % if the next uncommnon char is from Code A and not from B then % switch to mode A using . % else include and stay in mode B. \def\codeB #1#2#3\End{\addchar#1% \numofdigits#2#3\stop \ifnum\tempnum>3 \ifodd\tempnum\else \addtoks{99}\let\Next=\codeC \fi \else \ifx#2\End \let\Next=\finalcode \else \testchar{A:} #2% \ifchar \testnext{A:} #3\stop \ifnext \addtoks{101}\let\Next=\codeA \else \addtoks{98}\fi \fi \fi \fi \Next #2#3\End} % There is mode C. Test to change the mode: % If not next two chars are digits switch to code A or B by following rule: % If the next uncommon char is from Code A and not from B then % switch to mode A using % else switch to mode B using \def\codeC #1#2#3#4\End{\addtoks{#1#2}% \ifx#3\End \let\Next=\finalcode \else \testchar{D:} #3% \ifchar \def\temp{#4}% \ifx\temp\empty \switchtoAorB #3\stop \else \separate #4\stop \edef\act{\noexpand\testchar{D:}\temp}\act \ifchar \else \switchtoAorB #3#4\stop \fi \fi \else \switchtoAorB #3#4\stop \fi \fi \Next #3#4\End} \def\separate#1#2\stop{\def\temp{#1}} \def\switchtoAorB #1\stop{\testnext{A:} #1\stop \ifnext \addtoks{101}\let\Next=\codeA \else \addtoks{100}\let\Next=\codeB \fi} \def\finalcode\End\End{\addchecksum \addtok\stop \wlog{encoded: \the\icode}% \expandafter\makecode\the\icode} % \addchecksum adds the check sum into \icode \def\addchecksum{\tempnum=\chtotal \divide\tempnum by 103 \multiply\tempnum by 103 \advance\chtotal by-\tempnum \addtoks{\the\chtotal}} % The \makecode converts the \icode from format "\start,num,num,\stop," % into sequence of digits. Each digit repersents the multiple of X module % size for bar or space if it is at odd or even position. For example % 21141223311120. It means bar of 2X, space 1X, bar 1X, space 4X and so on. % This representation of code is stored in macro \internalcode. \def\makecode#1,{\let\next=\cyklcode \edef\internalcode{#1}\next} \def\cyklcode#1,{% \ifx\stop#1\let\next=\finalmakecode \edef\internalcode{\internalcode\stop}% \else \edef\internalcode{\internalcode\tableofcode{#1}}\fi \next} \def\finalmakecode{\wlog{black-white: \internalcode}% \begcode \let\next=\makebars \expandafter\makebars\internalcode} % \makebars simply makes the \vrules and \kerns of appropriate sizes from % \internalcode representation. Each width of \vrule is corrected by \bcorr % and opposite for \kern. \def\makebars#1#2{\if0#2\let\next=\endcode\fi \workdimen=#1\X \advance\workdimen by-\bcorr \vrule width\workdimen \workdimen=#2\X \advance\workdimen by \bcorr \kern\workdimen \next} % The begin and end of completed \hbox: \def\begcode{\hbox\bgroup\vrule height\barheight width0pt} \def\endcode{\egroup} % User can use \codetext or \codeothertext instead \code: \def\codeothertext#1#2{\vbox{\halign{\hfil##\hfil\cr\code{#1}\cr{\tt#2}\cr}}} \def\codetext#1{\codeothertext{#1}{#1}} \endinput %%%%%%%%%%%%%%% End of macros %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% The description of Code 128 standard ************************************ The characters from input string are converted from left to right to so called "output characters" by table 1 (see below). Each output character has three bars and spaces. The width of bars and the dimensions of spaces between bars are significant. This values are expresed by multiples of basic dimension: so called X module size (see \X in macro). The multiples varies from 1 to 4. We are using the six digits expression of output character. It expressed dimensions of bar, space, bar, space, bar, space. For example 122412 means one output character drawn as: 1X bar, 2X space, 2X bar, 4X space, 1X bar and 2X space. The table 1: num.line code A code B codeC output character ------------------------------------------------------- 0 [space] [space] 00 212222 1 ! ! 01 222122 2 " " 02 222221 3 # # 03 121223 ... and so on ... 63 _ _ 63 111224 64 \NUL ` 64 111422 65 \SOH a 65 121124 66 \STX b 66 121421 ... and so on ... 93 \GS } 93 111341 94 \RS ~ 94 131141 95 \US \DEL 95 114113 96 96 113311 97 97 411113 98 98 411311 99 99 113141 100 114131 101 311141 102 411131 The whole table is not presented here because you can simply reconstruct it from macros. The columns "code A", "code B", and "code C" inlude all possible input characters in input string (excluding "special commands" in lines 96--102 written in braces). The special \TeX{} characters must be escaped (i.e. user have to write \# and no #). The escaped words (in capitals) represents so called "control characters" from ASCII. The meaning of this sequences depends on application. The "special commands" in lines 96--102 written in braces are not possible in input. They are special for decoder. The and are used in our macro, but are not because they are reserved for special purposes. The Code B column is whole expressed in \definetable:0 (see in macro). The Code A column has the same values in lines 0--63 (capitals, digits and some other ASCII characters are included here). Code A differ from Code B in lines 64--102. The lowercase letters and another ASCII characters are included in "Code B", but control sequences are included in "Code A". The different part of "Code A" column is expressed in \definetable:64 (see in macro). The "code C" column includes the digits pairs and corresponds to number of line in table 1. Two digits in input go to one output character. The whole "output character" column is expressed in \tableofcode (see in macro). The "start character" is appended before each barcode. There are three types of start character depending on which column of table is used for next encoding (so called mode). See macros \startA, \startB and \startC. For examlpe: If \startC is used, next output character represents two digits in input (codeC mode). If \startB is used, next output character represents one ASCII character in input (codeB mode). If \startA is used, next output character represents probably the control sequence in input or capitals, but not lowercase ASCII (codeA mode). If some mode for encoding is currently used and next input character is not included in appropriate column, the "switching command" is included into sequence of output character. The command switches from mode A to B or from B to A only for one next input character and the other input characters are coded in the same mode (A or B). The command switches to codeA mode definitively unless next switch command is used. The commands and makes the same service, but to switch into mode B or C respectively. All these commands are expessed in table 1. It is recomended to chose the start character and switching commands by the way, that the resulting length of code is minimised. There are some recommendations of this choice. These recommendations are included into our macros (see the commnets and macros for \code, \codeA, \codeB and \codeC). The checksum character is added after the end of input string. Finally, the "stop character" is appended after the end of barcode. This character has exclusively four bars and not only three. See macro \stop. The checksum character is calculated from output characters used in the code. The number of line in table 1 of each output character is asumed. The start character is covered too, but checksum character itself and the stop character are not included into calculation. The startA or startB or startC characters has its number of line 103 or 104 or 105 respectively. Each output character (more exactly its number of line in table 1) is multiplied by "weight number" and the total sum is calculated. The weight number of start character is one. The weight number of first output characet after start is one too. Second character has weight number two, and so on. The n-th character has weight number n. The total sum modulo 103 is the line of the calculated checksum character. Example for checksum calculation: Input: 123456 Encoded: StartC, 12, 34, 56 Total sum of checksum: 105 + 1*12 + 2*34 + 3*56 = 535 Modulo 103: 44 The character from line 44 is apended as checksum. The whole encoded code: StartC, 12, 34, 56, 44, Stop %%% End of file. sdaps-1.9.8/tex/class/sdapslayout.dtx0000644000175000000660000005271313600505201020375 0ustar benjaminlock00000000000000% \iffalse meta-comment % % Copyright (C) 2014 by Henry Menke % Copyright (C) 2019 by Benjamin Berg % % This work may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3c % of this license or (at your option) any later version. % The latest version of this license is in % http://www.latex-project.org/lppl.txt % % This work has the LPPL maintenance status `maintained'. % % The Current Maintainer of this work is Benjamin Berg. % % \fi % % \iffalse %<*driver> \ProvidesFile{sdapslayout.dtx} % %\NeedsTeXFormat{LaTeX2e}[1999/12/01] %\ProvidesPackage{sdapslayout} %<*package> [2015/04/10 v0.1 Initial version of SDAPS layout package] % % %<*driver> \documentclass{l3doc} \usepackage{sdapslayout}[2015/04/10] \EnableCrossrefs %\CodelineIndex \RecordChanges \begin{document} \DocInput{sdapslayout.dtx} \end{document} % % \fi % % \CheckSum{0} % % \CharacterTable % {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z % Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z % Digits \0\1\2\3\4\5\6\7\8\9 % Exclamation \! Double quote \" Hash (number) \# % Dollar \$ Percent \% Ampersand \& % Acute accent \' Left paren \( Right paren \) % Asterisk \* Plus \+ Comma \, % Minus \- Point \. Solidus \/ % Colon \: Semicolon \; Less than \< % Equals \= Greater than \> Question mark \? % Commercial at \@ Left bracket \[ Backslash \\ % Right bracket \] Circumflex \^ Underscore \_ % Grave accent \` Left brace \{ Vertical bar \| % Right brace \} Tilde \~} % % % \changes{v0.1}{2015/01/14}{Initial version} % % \GetFileInfo{sdapslayout.dtx} % % \DoNotIndex{\newcommand,\newenvironment} % % % \title{The \textsf{sdapslayout} package\thanks{This document % corresponds to \textsf{sdapslayout}~\fileversion, dated \filedate.}} % \author{Benjamin Berg \\ \texttt{benjamin@sipsolutions.net}} % % \maketitle % % \section{Documentation} % % Please refer to \url{https://sdaps.org/class-doc} for documentation. % % \section{Implementation} % % This package uses the \LaTeX3 language internally, so we need to enable it. % \begin{macrocode} % We need at least 2011-08-23 for \keys_set_known:nnN \RequirePackage{expl3}[2011/08/23] %\RequirePackage{xparse} \ExplSyntaxOn % \end{macrocode} % % And we need a number of other packages. % \begin{macrocode} \ExplSyntaxOff \RequirePackage{sdapsbase} \RequirePackage{sdapsarray} \RequirePackage{xparse} \ExplSyntaxOn % \end{macrocode} % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % \subsection{Choice Question Layout} % % \subsubsection{Choice Question Matrix Layout} % % The following macros provide the funcitonality to layout choice questions in % a matrix like fashion. % % \begin{macrocode} \tl_new:N \l_sdaps_choicearray_qobject_type_tl \bool_new:N \l_sdaps_choicearray_horizontal_bool \tl_new:N \l_sdaps_choicearray_layouter_tl \tl_new:N \l_sdaps_choicearray_align_tl \tl_new:N \l_sdaps_choicearray_extra_tl \tl_new:N \l_sdaps_choicearray_type_tl \tl_new:N \l_sdaps_choice_var_tl \tl_new:N \l_sdaps_choice_val_tl \tl_new:N \l_sdaps_choice_text_tl \tl_new:N \l_sdaps_question_var_tl \tl_new:N \l_sdaps_question_text_tl \clist_new:N \l_sdaps_question_range_clist \int_new:N \g_sdaps_choices_box_int \seq_new:N \g_sdaps_choices_filter_seq \seq_new:N \g_sdaps_choices_cell_seq \seq_new:N \g_sdaps_choices_text_seq \keys_define:nn { sdaps / choicearray } { horizontal .bool_set:N = \l_sdaps_choicearray_horizontal_bool, horizontal .default:n = true, horizontal .initial:n = true, vertical .bool_set_inverse:N = \l_sdaps_choicearray_horizontal_bool, vertical .default:n = true, layouter .tl_set:N = \l_sdaps_choicearray_layouter_tl, layouter .initial:n = default, align .tl_set:N = \l_sdaps_choicearray_align_tl, align .initial:n = { }, type .choices:nn = { multichoice, singlechoice } { \tl_set:Nx \l_sdaps_choicearray_type_tl { \l_keys_choice_tl } }, type .initial:n = { multichoice }, singlechoice .meta:n = { type=singlechoice }, multichoice .meta:n = { type=multichoice }, noalign .meta:n = { align= }, } \keys_define:nn { sdaps / choicearray / choice } { var .tl_set:N = \l_sdaps_choice_var_tl, val .tl_set:N = \l_sdaps_choice_val_tl, text .tl_set:N = \l_sdaps_choice_text_tl, } \keys_define:nn { sdaps / choicearray / question } { var .tl_set:N = \l_sdaps_question_var_tl, text .tl_set:N = \l_sdaps_question_text_tl, range .clist_set:N = \l_sdaps_question_range_clist, range .initial:n = {...} } \cs_new_protected_nopar:Npn \_sdaps_choicearray_preprocess:n #1 { \keys_set_known:nnN { sdaps / choicearray } { #1 } \l_sdaps_choicearray_extra_tl \sdaps_checkbox_set_type:V \l_sdaps_choicearray_type_tl \tl_if_eq:VnTF \l_sdaps_choicearray_type_tl { multichoice } { \tl_set:Nn \l_sdaps_choicearray_qobject_type_tl { Choice } } { \tl_set:Nn \l_sdaps_choicearray_qobject_type_tl { Option } } } \cs_generate_variant:Nn \_sdaps_choicearray_preprocess:n { V } \cs_new_protected_nopar:Npn \_sdaps_choicearray_process_choice_insert_tail_after:w { \bgroup \group_insert_after:N \_sdaps_choicearray_process_choice_tail: \sdaps_array_nested_alignenv: \tex_let:D\next= } \cs_new_protected_nopar:Nn \_sdaps_choicearray_process_choice_tail: { \ignorespaces } \cs_new_nopar:Nn \_sdaps_choicearray_grab_choice:n { \seq_gput_right:Nn \g_sdaps_choices_text_seq { #1 } \group_begin: \sdaps_array_nested_alignenv: #1 \group_end: \_sdaps_choicearray_process_choice_tail: } \cs_new_nopar:Npn \_sdaps_choicearray_process_choice:nw #1 { % This modifies grouping so it has to be at the start \sdaps_array_alignment: \leavevmode \tl_clear:N \l_sdaps_choice_var_tl \tl_clear:N \l_sdaps_choice_val_tl \tl_clear:N \l_sdaps_choice_text_tl \keys_set:nn { sdaps / choicearray / choice } { #1 } \int_gincr:N \g_sdaps_choices_box_int \tl_if_empty:NT \l_sdaps_choice_var_tl { % Prefix with _ to force prefixing with generated variable \tl_set:Nx \l_sdaps_choice_var_tl { \int_use:N \g_sdaps_choices_box_int } } \tl_if_empty:NT \l_sdaps_choice_val_tl { \tl_set:Nx \l_sdaps_choice_val_tl { \int_use:N \g_sdaps_choices_box_int } } \tl_if_eq:VnTF \l_sdaps_choicearray_type_tl { multichoice } { \seq_gput_right:NV \g_sdaps_choices_filter_seq \l_sdaps_choice_var_tl } { \seq_gput_right:NV \g_sdaps_choices_filter_seq \l_sdaps_choice_val_tl } \seq_gput_right:Nx \g_sdaps_choices_cell_seq { \exp_not:n { \sdaps_checkbox:nn } { _ \l_sdaps_choice_var_tl } { \l_sdaps_choice_val_tl } } \tl_if_empty:NTF \l_sdaps_choice_text_tl { % We need to leave a command in the stream that grabs the next parameter % and outputs it immediately \cs_set_eq:NN \l_tmpa_token \_sdaps_choicearray_grab_choice:n } { % Nothing else to do \seq_gput_right:NV \g_sdaps_choices_text_seq { \l_sdaps_choice_text_tl } \cs_set_eq:NN \l_tmpa_token \_sdaps_choicearray_process_choice_insert_tail_after:w } \l_tmpa_token } \cs_generate_variant:Nn \_sdaps_choicearray_process_choice:nw { Vw } \cs_new_protected_nopar:Nn \_sdaps_choicearray_process_question_grab:n { \tl_set:Nn \l_sdaps_question_text_tl { #1 } \_sdaps_choicearray_process_question_head: \group_begin: \sdaps_array_nested_alignenv: #1 \group_end: \_sdaps_choicearray_process_question_tail: } \cs_new_protected_nopar:Npn \_sdaps_choicearray_process_question_inline:w { \_sdaps_choicearray_process_question_head: \bgroup \group_insert_after:N \_sdaps_choicearray_process_question_tail: \sdaps_array_nested_alignenv: \tex_let:D\next= } \cs_new_protected_nopar:Nn \_sdaps_choicearray_process_question_head: { \sdaps_qobject_begin:nnV { choicearray_question } \l_sdaps_choicearray_qobject_type_tl \l_sdaps_question_text_tl \tl_if_empty:NF \l_sdaps_question_var_tl { \sdaps_qobject_append_var:V \l_sdaps_question_var_tl } } \cs_new_protected_nopar:Nn \_sdaps_choicearray_process_question_tail: { \seq_gclear:N \g_tmpa_seq % l_tmpa_bool is whether we are in a run (i.e. ...) \bool_set_false:N \l_tmpa_bool \clist_gset_eq:NN \g_tmpa_clist \l_sdaps_question_range_clist \clist_gpop:NN \g_tmpa_clist \l_tmpa_tl \seq_map_inline:Nn \g_sdaps_choices_filter_seq { \tl_if_eq:VnT \l_tmpa_tl { ... } { \bool_set_true:N \l_tmpa_bool \clist_gpop:NN \g_tmpa_clist \l_tmpa_tl } \tl_if_eq:VnTF \l_tmpa_tl { ##1 } { \seq_gput_right:Nn \g_tmpa_seq { \c_true_bool } \bool_set_false:N \l_tmpa_bool \clist_gpop:NN \g_tmpa_clist \l_tmpa_tl } { % Append if we are handling a run of items and the current item is not % the last one. \bool_if:NTF \l_tmpa_bool { \seq_gput_right:Nn \g_tmpa_seq { \c_true_bool } } { % Otherwise, ignore this item \seq_gput_right:Nn \g_tmpa_seq { \c_false_bool } } } } \seq_gset_eq:NN \g_tmpb_seq \g_tmpa_seq \seq_map_inline:Nn \g_sdaps_choices_text_seq { \seq_gpop_left:NN \g_tmpa_seq \l_tmpa_tl \tl_if_eq:VnT \l_tmpa_tl { \c_true_bool } { \sdaps_answer:f { ##1 } } } \seq_map_inline:Nn \g_sdaps_choices_cell_seq { \sdaps_array_alignment: \seq_gpop_left:NN \g_tmpb_seq \l_tmpa_tl \tl_if_eq:VnT \l_tmpa_tl { \c_true_bool } { ##1 } } \sdaps_qobject_end:n { choicearray_question } \ignorespaces } \cs_new_nopar:Npn \_sdaps_choicearray_process_question:nw #1 { \sdaps_array_newline: \leavevmode \keys_set:nn { sdaps / choicearray / question } { #1 } \tl_if_empty:NTF \l_sdaps_question_text_tl { % We need to leave a command in the stream that grabs the next parameter, % outputs it again, and finishes the question. \cs_set_eq:NN \l_tmpa_token \_sdaps_choicearray_process_question_grab:n } { % Insert the question around the next argument \cs_set_eq:NN \l_tmpa_token \_sdaps_choicearray_process_question_inline:w } \l_tmpa_token } \cs_generate_variant:Nn \_sdaps_choicearray_process_question:nw { Vw } % % \end{macrocode} % % % \subsection{Range Question Layout} % % \subsubsection{Range Question Matrix Layout} % % The following macros provide the functionality to layout range/option % questions in a matrix like fashion. % % \begin{macrocode} \tl_new:N \l_sdaps_rangearray_align_tl \tl_new:N \l_sdaps_rangearray_extra_tl \int_new:N \l_sdaps_rangearray_rangecount_int \bool_new:N \l_sdaps_rangearray_other_bool \tl_new:N \g_sdaps_question_var_tl \tl_new:N \g_sdaps_question_text_tl \tl_new:N \g_sdaps_question_lowertext_tl \tl_new:N \g_sdaps_question_uppertext_tl \tl_new:N \g_sdaps_question_othertext_tl \msg_new:nnn { sdapslayout } { option_not_supported } { The~#1~option~is~not~supported~by~this~environment. } \keys_define:nn { sdaps / rangearray } { count .int_set:N = \l_sdaps_rangearray_rangecount_int, count .initial:n = 5, align .tl_set:N = \l_sdaps_rangearray_align_tl, align .initial:n = { }, % Override and disallow flipping; it does not work currently flip .code:n = { \msg_error:nnn { sdapslayout } { option_not_supported } { flip } }, other .bool_set:N = \l_sdaps_rangearray_other_bool, other .default:n = true, other .initial:n = false, } \keys_define:nn { sdaps / rangearray / question } { var .tl_gset:N = \g_sdaps_question_var_tl, text .tl_gset:N = \g_sdaps_question_text_tl, upper .tl_gset:N = \g_sdaps_question_uppertext_tl, lower .tl_gset:N = \g_sdaps_question_lowertext_tl, other .tl_gset:N = \g_sdaps_question_othertext_tl, } \cs_new_protected_nopar:Npn \_sdaps_rangearray_preprocess:n #1 { \keys_set_known:nnN { sdaps / rangearray } { #1 } \l_sdaps_rangearray_extra_tl \sdaps_checkbox_set_type:n { singlechoice } } \cs_generate_variant:Nn \_sdaps_rangearray_preprocess:n { V } % Before/After the different parts \cs_new_protected_nopar:Nn \_sdaps_rangearray_process_question_before_question: { \sdaps_array_newline: % Note: This needs to be after sdaps_array_newline as the command may be % discarded otherwise (i.e. it does not make it into the output stream) % We also need to leave vmode here \leavevmode \sdaps_qobject_begin:nnV { rangearray_question } { Range } \g_sdaps_question_text_tl \tl_if_empty:NF \g_sdaps_question_var_tl { \sdaps_qobject_append_var:V \g_sdaps_question_var_tl } \ignorespaces } \cs_new_protected_nopar:Nn \_sdaps_rangearray_process_question_before_lower: { % right align \sdaps_array_alignment: \leavevmode \sdaps_range:nnV { lower } { 0 } \g_sdaps_question_lowertext_tl \sdaps_if_rtl:F { \hfill } \ignorespaces } \cs_new_protected_nopar:Nn \_sdaps_rangearray_process_question_before_upper: { \sdaps_array_alignment: \leavevmode \sdaps_range:nnV { upper } { \l_sdaps_rangearray_rangecount_int - 1 } \g_sdaps_question_uppertext_tl \sdaps_if_rtl:T { \hfill } \ignorespaces } \cs_new_protected_nopar:Nn \_sdaps_rangearray_process_question_before_other: { % Insert an extra empty column for further spacing \sdaps_array_alignment: \sdaps_array_alignment: \leavevmode \sdaps_answer:V \g_sdaps_question_othertext_tl \sdaps_if_rtl:TF { \hfill } { \sdaps_checkbox:nn { } { 0 } {} ~ {} } \ignorespaces } \cs_new_protected_nopar:Nn \_sdaps_rangearray_process_question_after_question: { % Insert an extra empty column for further spacing \sdaps_array_alignment: \tl_if_empty:NTF \g_sdaps_question_lowertext_tl { \cs_set_eq:NN \l_tmpa_token \_sdaps_rangearray_process_question_grab_lower:n } { \cs_set_eq:NN \l_tmpa_token \_sdaps_rangearray_process_question_inline_lower:w } \l_tmpa_token } \cs_new_protected_nopar:Nn \_sdaps_rangearray_process_question_after_lower: { % Insert the option checkbox column \sdaps_if_rtl:T { \hfill\kern 0pt } \sdaps_array_alignment: \leavevmode % Seems like right to left writing mode is not started without a paragraph \sdaps_if_rtl:T { \beginR } % Assume we have at least one checkbox \sdaps_checkbox:nn { } { 1 } \int_step_inline:nnnn { 2 } { 1 } { \l_sdaps_rangearray_rangecount_int } { \hspace{1em} \sdaps_checkbox:nn { } { ##1 } } \sdaps_if_rtl:T { \endR } \tl_if_empty:NTF \g_sdaps_question_uppertext_tl { \cs_set_eq:NN \l_tmpa_token \_sdaps_rangearray_process_question_grab_upper:n } { \cs_set_eq:NN \l_tmpa_token \_sdaps_rangearray_process_question_inline_upper:w } \l_tmpa_token } \cs_new_protected_nopar:Nn \_sdaps_rangearray_process_question_after_upper: { \sdaps_if_rtl:F { \hfill\kern 0pt } \bool_if:NTF \l_sdaps_rangearray_other_bool { \tl_if_empty:NTF \g_sdaps_question_othertext_tl { \cs_set_eq:NN \l_tmpa_token \_sdaps_rangearray_process_question_grab_other:n } { \cs_set_eq:NN \l_tmpa_token \_sdaps_rangearray_process_question_inline_other:w } } { \cs_set_eq:NN \l_tmpa_token \_sdaps_rangearray_process_question_finish: } \l_tmpa_token } \cs_new_protected_nopar:Nn \_sdaps_rangearray_process_question_after_other: { \sdaps_if_rtl:TF { {} ~ \sdaps_checkbox:nn { } { 0 } {} } { \hfill\kern 0pt } \ignorespaces } \cs_new_protected_nopar:Nn \_sdaps_rangearray_process_question_finish: { \sdaps_qobject_end:n { rangearray_question } \ignorespaces } % Processors for inline processing/grabbing the argument \cs_new_protected_nopar:Nn \_sdaps_rangearray_process_question_grab_question:n { \tl_gset:Nn \g_sdaps_question_text_tl { #1 } \_sdaps_rangearray_process_question_before_question: \group_begin: \sdaps_array_nested_alignenv: #1 \group_end: \_sdaps_rangearray_process_question_after_question: } \cs_new_protected_nopar:Nn \_sdaps_rangearray_process_question_grab_lower:n { \tl_gset:Nn \g_sdaps_question_lowertext_tl { #1 } \_sdaps_rangearray_process_question_before_lower: \group_begin: \sdaps_array_nested_alignenv: #1 \group_end: \_sdaps_rangearray_process_question_after_lower: } \cs_new_protected_nopar:Nn \_sdaps_rangearray_process_question_grab_upper:n { \tl_gset:Nn \g_sdaps_question_uppertext_tl { #1 } \_sdaps_rangearray_process_question_before_upper: \group_begin: \sdaps_array_nested_alignenv: #1 \group_end: \_sdaps_rangearray_process_question_after_upper: } \cs_new_protected_nopar:Nn \_sdaps_rangearray_process_question_grab_other:n { \tl_gset:Nn \g_sdaps_question_othertext_tl { #1 } % If the text is empty, assume that this particular question does not have % an alternative choice. Note that this column might not exist and this % macro will not even be called in that case. % If we skip the optional "other" option then we still need to insert the % alignment to create the column. \tl_if_empty:NTF \g_sdaps_question_othertext_tl { \sdaps_array_alignment: \leavevmode \ignorespaces } { \_sdaps_rangearray_process_question_before_other: \group_begin: \sdaps_array_nested_alignenv: #1 \group_end: \_sdaps_rangearray_process_question_after_other: } \_sdaps_rangearray_process_question_finish: } \cs_new_protected_nopar:Npn \_sdaps_rangearray_process_question_inline_question:w { \_sdaps_rangearray_process_question_before_question: \bgroup \group_insert_after:N \_sdaps_rangearray_process_question_after_question: \sdaps_array_nested_alignenv: \tex_let:D\next= } \cs_new_protected_nopar:Npn \_sdaps_rangearray_process_question_inline_lower:w { \_sdaps_rangearray_process_question_before_lower: \bgroup \group_insert_after:N \_sdaps_rangearray_process_question_after_lower: \tex_let:D\next= } \cs_new_protected_nopar:Npn \_sdaps_rangearray_process_question_inline_upper:w { \_sdaps_rangearray_process_question_before_upper: \bgroup \group_insert_after:N \_sdaps_rangearray_process_question_after_upper: \tex_let:D\next= } \cs_new_protected_nopar:Npn \_sdaps_rangearray_process_question_inline_other:w { \_sdaps_rangearray_process_question_before_other: % If we reach this macro then a text has been set for the other item. This % means we never need to ignore the "other" parameter at this point. \bgroup \group_insert_after:N \_sdaps_rangearray_process_question_after_other: \group_insert_after:N \_sdaps_rangearray_process_question_finish: \tex_let:D\next= } \cs_new_nopar:Npn \_sdaps_rangearray_process_question:nw #1 { % Is there a better way other than clearing these before parsing? \tl_gclear:N \g_sdaps_question_var_tl \tl_gclear:N \g_sdaps_question_text_tl \tl_gclear:N \g_sdaps_question_uppertext_tl \tl_gclear:N \g_sdaps_question_lowertext_tl \tl_gclear:N \g_sdaps_question_othertext_tl \keys_set:nn { sdaps / rangearray / question } { #1 } \tl_if_empty:NTF \g_sdaps_question_text_tl { % We need to leave a command in the stream that grabs the next parameter, % outputs it again, and finishes the question. \cs_set_eq:NN \l_tmpa_token \_sdaps_rangearray_process_question_grab_question:n } { % We need to generate the question after the next group stops \cs_set_eq:NN \l_tmpa_token \_sdaps_rangearray_process_question_inline_question:w } \l_tmpa_token } \cs_generate_variant:Nn \_sdaps_rangearray_process_question:nw { Vw } % % \end{macrocode} % % % % \subsection{Export user facing environments} % % \begin{macrocode} % \newenvironment { choicearray } [ 1 ] [] { \group_begin: \sdaps_context_get:nN { choicearray } \l_tmpa_tl \tl_if_eq:NNT \l_tmpa_tl \q_no_value { \tl_set:Nn \l_tmpa_tl {} } \tl_if_empty:nF { #1 } { \tl_if_empty:NTF \l_tmpa_tl { \tl_set:Nn \l_tmpa_tl { #1 } } { \tl_set:Nf \l_tmpa_tl { \l_tmpa_tl, #1 } } } \_sdaps_choicearray_preprocess:V \l_tmpa_tl % Clear the variables \seq_gclear:N \g_sdaps_choices_filter_seq \seq_gclear:N \g_sdaps_choices_cell_seq \seq_gclear:N \g_sdaps_choices_text_seq \int_gzero:N \g_sdaps_choices_box_int % Define new commands \newcommand \choice [ 1 ] [] { \_sdaps_choicearray_process_choice:nw { ##1 } } \newcommand \question [ 1 ] [] { \_sdaps_choicearray_process_question:nw { ##1 } } \group_begin: \tl_set:Nx \l_tmpb_tl {keepenv,layouter=\tl_use:N\l_sdaps_choicearray_layouter_tl,align=\l_sdaps_choicearray_align_tl\bool_if:NF\l_sdaps_choicearray_horizontal_bool{,flip},\l_sdaps_choicearray_extra_tl} \expandafter\sdapsarray\expandafter[\l_tmpb_tl] } { \endsdapsarray \group_end: \group_end: } \newenvironment { optionarray } [ 1 ] [] { \choicearray[singlechoice,#1] } { \endchoicearray } \newenvironment { rangearray } [ 1 ] [] { \group_begin: \sdaps_context_get:nN { rangearray } \l_tmpa_tl \tl_if_eq:NNT \l_tmpa_tl \q_no_value { \tl_set:Nn \l_tmpa_tl {} } \tl_if_empty:nF { #1 } { \tl_if_empty:NTF \l_tmpa_tl { \tl_set:Nn \l_tmpa_tl { #1 } } { \tl_set:Nf \l_tmpa_tl { \l_tmpa_tl, #1 } } } \_sdaps_rangearray_preprocess:V \l_tmpa_tl \newcommand \range [ 1 ] [] { \_sdaps_rangearray_process_question:nw { ##1 } } \group_begin: \tl_set:Nx \l_tmpb_tl {keepenv,align=\l_sdaps_rangearray_align_tl,no_header,\l_sdaps_rangearray_extra_tl} \expandafter\sdapsarray\expandafter[\l_tmpb_tl] } { \endsdapsarray \group_end: \group_end: } \ExplSyntaxOff % % \end{macrocode} % % \iffalse % \PrintChanges % \PrintIndex % \fi % % \Finale \endinput sdaps-1.9.8/tex/class/sdapslayout.ins0000644000175000000660000000354713600505201020370 0ustar benjaminlock00000000000000%% %% Copyright (C) 2015 by Benjamin Berg %% %% This work may be distributed and/or modified under the %% conditions of the LaTeX Project Public License, either version 1.3c %% of this license or (at your option) any later version. %% The latest version of this license is in %% http://www.latex-project.org/lppl.txt %% %% This work has the LPPL maintenance status `maintained'. %% %% The Current Maintainer of this work is Benjamin Berg. %% \input l3docstrip.tex \keepsilent \usedir{tex/latex/cskeleton} \preamble This is a generated file. Copyright (C) 2015 by Benjamin Berg This work may be distributed and/or modified under the conditions of the LaTeX Project Public License, either version 1.3c of this license or (at your option) any later version. The latest version of this license is in http://www.latex-project.org/lppl.txt \endpreamble \generate{\file{sdapslayout.sty}{\from{sdapslayout.dtx}{package}}} \obeyspaces \Msg{*************************************************************} \Msg{* *} \Msg{* To finish the installation you have to move the following *} \Msg{* file into a directory searched by TeX: *} \Msg{* *} \Msg{* sdapslayout.cls *} \Msg{* *} \Msg{* To produce the documentation run the file sdapslayout.dtx *} \Msg{* through LaTeX. *} \Msg{* *} \Msg{* Happy TeXing! *} \Msg{* *} \Msg{*************************************************************} \endbatchfile sdaps-1.9.8/tex/class/sdapspdf.dtx0000644000175000000660000001206313600505201017623 0ustar benjaminlock00000000000000% \iffalse meta-comment % % Copyright (C) 2014 by Henry Menke % Copyright (C) 2019 by Benjamin Berg % % This work may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3c % of this license or (at your option) any later version. % The latest version of this license is in % http://www.latex-project.org/lppl.txt % % This work has the LPPL maintenance status `maintained'. % % The Current Maintainer of this work is Benjamin Berg. % % \fi % % \iffalse %<*driver> \ProvidesFile{sdapspdf.dtx} % %\NeedsTeXFormat{LaTeX2e}[1999/12/01] %\ProvidesPackage{sdapspdf} %<*package> [2015/04/10 v0.1 Initial version of SDAPS pdf package] % % %<*driver> \documentclass{ltxdoc} \usepackage{sdapspdf}[2015/04/10] %\EnableCrossrefs \CodelineIndex \RecordChanges \begin{document} \DocInput{sdapspdf.dtx} \end{document} % % \fi % % \CheckSum{0} % % \CharacterTable % {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z % Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z % Digits \0\1\2\3\4\5\6\7\8\9 % Exclamation \! Double quote \" Hash (number) \# % Dollar \$ Percent \% Ampersand \& % Acute accent \' Left paren \( Right paren \) % Asterisk \* Plus \+ Comma \, % Minus \- Point \. Solidus \/ % Colon \: Semicolon \; Less than \< % Equals \= Greater than \> Question mark \? % Commercial at \@ Left bracket \[ Backslash \\ % Right bracket \] Circumflex \^ Underscore \_ % Grave accent \` Left brace \{ Vertical bar \| % Right brace \} Tilde \~} % % % \changes{v0.1}{2015/01/14}{Initial version} % % \GetFileInfo{sdapspdf.dtx} % % \DoNotIndex{\newcommand,\newenvironment} % % % \title{The \textsf{sdapspdf} package\thanks{This document % corresponds to \textsf{sdapspdf}~\fileversion, dated \filedate.}} % \author{Benjamin Berg \\ \texttt{benjamin@sipsolutions.net}} % % \maketitle % % \section{Documentation} % % Please refer to \url{https://sdaps.org/class-doc} for documentation. % % \StopEventually{\PrintChanges\PrintIndex} % % \section{Implementation} % % This package uses the \LaTeX3 language internally, so we need to enable it. % \begin{macrocode} % We need at least 2011-08-23 for \keys_set_known:nnN \RequirePackage{expl3}[2011/08/23] %\RequirePackage{xparse} \ExplSyntaxOn % \end{macrocode} % % And we need a number of other packages. % \begin{macrocode} \ExplSyntaxOff \RequirePackage{sdapsbase} \RequirePackage{hyperref} \ExplSyntaxOn % \end{macrocode} % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % \subsection{PDF Support} % % This package adds basic overlays to SDAPS boxes so that they become editable. % It is also possible to pre-fill them using overrides or the normal mechanism % to set variables for box drawing. % % \begin{macrocode} \bool_new:N \l__sdaps_pdf_form_bool \bool_new:N \l__sdaps_pdf_checkbox_default_bool \tl_new:N \l__sdaps_pdf_checkboxsymbol_tl \keys_define:nn { sdaps / checkbox / overlay / pdfform } { pdf_form .bool_set:N = \l__sdaps_pdf_form_bool, pdf_form .initial:n = false, default .bool_set:N = \l__sdaps_pdf_checkbox_default_bool, default .initial:n = false, checkboxsymbol .tl_set:N = \l__sdaps_pdf_checkboxsymbol_tl, checkboxsymbol .initial:n = 8, } \cs_new_protected_nopar:Nn \_sdaps_pdf_overlay_checkbox_form: { \keys_set_known:nV { sdaps / checkbox / overlay / pdfform } { \l_sdaps_parse_unknown_tl } % \bool_if:NT \l__sdaps_pdf_form_bool { \node[anchor=center,inner~sep=0pt,outer~sep=0pt] at ($(\l_sdaps_x_dim, \l_sdaps_y_dim) + 0.5*(\l_sdaps_width_dim, -\l_sdaps_height_dim)$) { \CheckBox[name=\l_sdaps_var_tl,bordersep=0,borderwidth=0pt,checkboxsymbol=\l__sdaps_pdf_checkboxsymbol_tl,bordercolor=,backgroundcolor=,checked=\bool_if:nTF\l__sdaps_pdf_checkbox_default_bool{true}{false},height=\l_sdaps_checkbox_height_dim,width=\l_sdaps_checkbox_width_dim]{\ignorespaces} }; } } \seq_put_left:Nn \g__sdaps_checkbox_overlays_seq \_sdaps_pdf_overlay_checkbox_form: \cs_new_protected_nopar:Nn \_sdaps_pdf_overlay_text_form: { \keys_set_known:nV { sdaps / checkbox / overlay / pdfform } { \l_sdaps_parse_unknown_tl } % \bool_if:NT \l__sdaps_pdf_form_bool { \node[anchor=center,inner~sep=2pt,outer~sep=0pt] at ($(\l_sdaps_x_dim, \l_sdaps_y_dim) + 0.5*(\l_sdaps_width_dim, -\l_sdaps_height_dim)$) { \dim_set:Nn \l_sdaps_width_dim { \l_sdaps_width_dim - 4pt } \dim_set:Nn \l_sdaps_height_dim { \l_sdaps_height_dim - 4pt } \TextField[name=\l_sdaps_var_tl,bordersep=0pt,borderwidth=0pt,bordercolor=,backgroundcolor=,multiline=true,height=\l_sdaps_height_dim,width=\l_sdaps_width_dim]{\ignorespaces} }; } } \seq_put_left:Nn \g__sdaps_textbox_overlays_seq \_sdaps_pdf_overlay_text_form: \ExplSyntaxOff % % \end{macrocode} % % \Finale \endinput sdaps-1.9.8/tex/class/sdapspdf.ins0000644000175000000660000000354113600505201017616 0ustar benjaminlock00000000000000%% %% Copyright (C) 2015 by Benjamin Berg %% %% This work may be distributed and/or modified under the %% conditions of the LaTeX Project Public License, either version 1.3c %% of this license or (at your option) any later version. %% The latest version of this license is in %% http://www.latex-project.org/lppl.txt %% %% This work has the LPPL maintenance status `maintained'. %% %% The Current Maintainer of this work is Benjamin Berg. %% \input l3docstrip.tex \keepsilent \usedir{tex/latex/cskeleton} \preamble This is a generated file. Copyright (C) 2015 by Benjamin Berg This work may be distributed and/or modified under the conditions of the LaTeX Project Public License, either version 1.3c of this license or (at your option) any later version. The latest version of this license is in http://www.latex-project.org/lppl.txt \endpreamble \generate{\file{sdapspdf.sty}{\from{sdapspdf.dtx}{package}}} \obeyspaces \Msg{*************************************************************} \Msg{* *} \Msg{* To finish the installation you have to move the following *} \Msg{* file into a directory searched by TeX: *} \Msg{* *} \Msg{* sdapspdf.cls *} \Msg{* *} \Msg{* To produce the documentation run the file sdapspdf.dtx *} \Msg{* through LaTeX. *} \Msg{* *} \Msg{* Happy TeXing! *} \Msg{* *} \Msg{*************************************************************} \endbatchfile sdaps-1.9.8/tex/class/testfiles/0000755000175000000660000000000013611127124017304 5ustar benjaminlock00000000000000sdaps-1.9.8/tex/class/testfiles/array.lvt0000644000175000000660000005111513416727013021162 0ustar benjaminlock00000000000000\documentclass{scrartcl} \input{regression-test} \OMIT \usepackage{sdapsarray} \usepackage{multicol} \def\logpos#1{\lognamedpos{#1}#1} \def\lognamedpos#1{\leavevmode\pdfsavepos\write128{POSITION #1: \the\pdflastxpos,\the\pdflastypos}} \newenvironment{MYTEST}[1]{% \begingroup% \global\advance \gTESTint 1 % \SEPARATOR% \LONGTYPEOUT{% TEST \the\gTESTint: \detokenize{#1}}% \SEPARATOR% }{% \SEPARATOR% \LONGTYPEOUT{}% \endgroup% } \newenvironment{OMITPAGE}{% \begingroup% \OMIT% }{% \vfil\break% \TIMO% \endgroup% } \newenvironment{MYTESTPAGE}[1]{% \begin{MYTEST}{#1}% }{% \vfil\break% \end{MYTEST}% } \newenvironment{MYTESTPAGESHOW}[1]{% \begin{MYTESTPAGE}{#1}% \showoutput% }{% \end{MYTESTPAGE}% } \TIMO \begin{document} \START \begin{OMITPAGE} % Some font stuff $ a + b $ % Open some extra temporary files \begin{sdapsarray} a & b & c \\ d & e & f \end{sdapsarray} \end{OMITPAGE} %\begin{MYTESTPAGE}{not shown} % blub %\end{MYTESTPAGE} %\begin{MYTESTPAGESHOW}{shown} % blub %\end{MYTESTPAGESHOW} %\begin{MYTESTPAGESHOW}{shown} % \begin{tabular}{cc} % a & ab \\ % c & d % \end{tabular} %\end{MYTESTPAGESHOW} \begin{MYTESTPAGE}{Basic alignment and layout} % Simply three arrays, first creating an alignment, then use it and a third % independent alignment. \begin{sdapsarray}[align=test1] \logpos{row head} & \logpos{col head 1} & \logpos{col head 2} \\ \logpos{row head 2} & \logpos{a} & \logpos{b} \\ \logpos{row head 3} & \logpos{c} & \logpos{d} \end{sdapsarray} \hrule \begin{sdapsarray}[align=test1] h & \logpos{a} & \logpos{b} \\ \logpos{aligned head} & \logpos{c} & \logpos{d} \end{sdapsarray} \hrule \begin{sdapsarray}[align=other1] h & \logpos{e} & \logpos{f} \\ \logpos{unaligned head} & \logpos{g} & \logpos{h} \end{sdapsarray} \end{MYTESTPAGE} \begin{MYTESTPAGE}{Spaces in cells are not relevant} \begin{sdapsarray} h & \logpos{a} & \logpos{b} \\ h && \logpos{d} \end{sdapsarray} \begin{sdapsarray} h&\logpos{a}&\logpos{b}\\% h&&\logpos{d}% \end{sdapsarray} % Also test the flip case as the parser is different \begin{sdapsarray}[flip] h & \logpos{a} & \logpos{b} \\ h & & \logpos{d} \end{sdapsarray} \begin{sdapsarray}[flip] h&\logpos{a}&\logpos{b}\\% h& &\logpos{d}% \end{sdapsarray} \end{MYTESTPAGE} \begin{MYTESTPAGE}{Cells can be right/left aligned using hfill/vfill} \begin{sdapsarray} {} & \logpos{column} & \logpos{column} \\ head & \hfill\logpos{x} & \hfill\logpos{x} \\ head & \logpos{x} & \logpos{x} \\ head & \logpos{x}\hfill{} & \logpos{x}\hfill{} \\ head &\hfill\logpos{x}&\hfill\logpos{x}\\ head &\logpos{x}&\logpos{x}\\ head &\logpos{x}\hfill{}\kern 0pt&\logpos{x}\hfill{}\kern 0pt% \end{sdapsarray} \begin{sdapsarray}[flip] & \logpos{column} & \logpos{column} \\ head & \hfill\logpos{x} & \hfill\logpos{x} \\ head & \logpos{x} & \logpos{x} \\ head & \logpos{x}\hfill{} & \logpos{x}\hfill{} \\ head &\hfill\logpos{x}&\hfill\logpos{x}\\ head &\logpos{x}&\logpos{x}\\ head &\logpos{x}\hfill{}\kern 0pt&\logpos{x}\hfill{}\kern 0pt% \end{sdapsarray} \end{MYTESTPAGE} \begin{MYTESTPAGE}{Fliptest} % Simple flip test. First non-flipped then flipped version. \begin{sdapsarray}[align=test2] \logpos{row head} & \logpos{col head 1} & \logpos{col head 2} \\ \logpos{row head 2} & \logpos{a} & \logpos{b} \\ \logpos{row head 3} & \logpos{c} & \logpos{d} \end{sdapsarray} \hrule \begin{sdapsarray}[flip,align=test2] \logpos{row head} & \logpos{col head 1} & \logpos{col head 2} \\ \logpos{row head 2} & \logpos{a} & \logpos{b} \\ \logpos{row head 3} & \logpos{c} & \logpos{d} \end{sdapsarray} \end{MYTESTPAGE} \begin{MYTESTPAGE}{sdapsarray spanning a multicol environment} % the header will be repeated \begin{multicols}{2} \begin{sdapsarray} \logpos{row head}\vrule height 2em depth 1em & \logpos{col head 1} & \logpos{col head 2} \\ \logpos{row head 1} & \logpos{a} & \logpos{b} \\ \logpos{row head 2} \vrule height 2em depth 1em & \logpos{c} & \logpos{d} \\ \logpos{row head 3} & \logpos{e} & \logpos{f} \\ \logpos{row head 4} & \logpos{g} & \logpos{h} \\ \logpos{row head 5} & \logpos{i} & \logpos{j} \\ \logpos{row head 6} & \logpos{k} & \logpos{l} \\ \logpos{row head 7} & \logpos{m} & \logpos{n} \end{sdapsarray} \end{multicols} \end{MYTESTPAGE} \begin{MYTESTPAGE}{sdapsarray not splitting with huge penalty} \ExplSyntaxOn \int_set:Nn \g_sdaps_array_row_penalty_tl { 10000 } \ExplSyntaxOff % All of this will be in the first column becaues of the huge penalty % (effectively a \nobreak) above. \begin{multicols}{2} \begin{sdapsarray} row head & col 1 & col 2 \\ row head 1 & a & \logpos{a} \\ row head 2 & a & a \\ row head 3 & a & a \\ row head 4 & a & a \\ row head 5 & a & a \\ row head 6 & a & a \\ row head 7 & a & a \\ row head 8 & a & a \\ row head 9 & a & a \\ row head 10 & a & a \\ row head 11 & a & a \\ row head 12 & a & a \\ row head 13 & a & a \\ row head 14 & a & a \\ row head 15 & a & a \\ row head 16 & a & a \\ row head 17 & a & a \\ row head 18 & a & a \\ row head 19 & a & a \\ row head 20 & a & \logpos{a} \end{sdapsarray} \end{multicols} \end{MYTESTPAGE} \begin{MYTESTPAGE}{sdapsarray should discourage being split over pages} Some filler text (just so that the skip is not discarded) \vskip 45em And add some more variable glue after this. \vfil And the array is below this, but we end this paragraph first. \begin{sdapsarray} row head & col 1 & col 2 \\ row head 1 & a & \logpos{a} \\ row head 2 & a & a \\ row head 3 & a & a \\ row head 4 & a & a \\ row head 5 & a & a \\ row head 6 & a & a \\ row head 7 & a & a \\ row head 8 & a & a \\ row head 9 & a & a \\ row head 10 & a & \logpos{a} \end{sdapsarray} \end{MYTESTPAGE} \begin{MYTESTPAGE}{sdapsarray with rotated header} % Rotated header test. This is a bit of a cludge as we only test the % positioning of the box and rotation is not actually tested. % But for example "row head" is higher than "col head X". \begin{sdapsarray}[layouter=rotated] \logpos{row head} & \lognamedpos{col head 1}\sdapsnested{$\frac{1}{\left( \begin{array}{cc} a & b \\ c & d \end{array} \right) + \log{\alpha}}$} & \lognamedpos{col head 2}\sdapsnested{$\log{\alpha} + \left[ \begin{array}{cc} a & b \\ c & d \end{array} \right]$} \\ \logpos{row head 1} & \logpos{a} & \logpos{b} \\ \logpos{row head 2} & \logpos{c} & \logpos{d} \\ \logpos{row head 3} & \logpos{e} & \logpos{f} \end{sdapsarray} \begin{sdapsarray}[layouter=rotated,angle=45] \logpos{row head} & \logpos{col head 1} & \logpos{col head 2} \\ \logpos{row head 1} & \logpos{a} & \logpos{b} \\ \logpos{row head 2} & \logpos{c} & \logpos{d} \\ \logpos{row head 3} & \logpos{e} & \logpos{f} \end{sdapsarray} \end{MYTESTPAGE} \begin{MYTESTPAGE}{sdapsarray with rotated header} % Rotated header test. This is a bit of a cludge as we only test the % positioning of the box and rotation is not actually tested. % But for example "row head" is higher than "col head X". \begin{sdapsarray}[layouter=rotated,align=test-rotated-header-align] \logpos{row head} & \logpos{col head 1} & \logpos{col head 2} \\ \logpos{row head 1} & \logpos{a} & \logpos{b} \\ \logpos{row head 2} & \logpos{c} & \logpos{d} \\ \logpos{row head 3} & \logpos{e} & \logpos{f} \end{sdapsarray} \begin{sdapsarray}[layouter=rotated,align=test-rotated-header-align] \logpos{row head} & \logpos{col head 1} & \logpos{col head 2 with extra long text} \\ \logpos{row head 1} & \logpos{a} & \logpos{b} \\ \logpos{row head 2} & \logpos{c} & \logpos{d} \\ \logpos{row head 3} & \logpos{e} & \logpos{f} \end{sdapsarray} \end{MYTESTPAGE} \begin{MYTESTPAGE}{sdapsarray with multiline row header} % The row headers can be multiline and should properly flow as paragraphs. % They are ragged right though towards the cells. \begin{sdapsarray} {} & col 1 & col 2 \\ \logpos{A row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{a} & \logpos{b} \\ \logpos{Another row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{a} & \logpos{b} \\ \logpos{Another row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{a} & \logpos{b} \\ \logpos{Another row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{a} & \logpos{b} \\ \logpos{Another row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{a} & \logpos{b} \\ \logpos{row head 2} & \logpos{c} & \logpos{d} \\ asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf & col 1 & col 2 \end{sdapsarray} \noindent x \hrule \begin{sdapsarray}[flip] & \logpos{A row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{Another row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{Another row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{Another row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{Another row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. \\ col 1 & \logpos{a} & \logpos{a} & \logpos{a} & \logpos{a} & \logpos{a} \\ col 2 & \logpos{b} & \logpos{b} & \logpos{b} & \logpos{b} & \logpos{b} \end{sdapsarray} \end{MYTESTPAGE} \begin{MYTESTPAGE}{sdapsarray inside an addmargin environment} \begin{addmargin}{5em} \begin{sdapsarray} {} & col 1 & col 2 \\ \logpos{A row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{a} & \logpos{b} \\ \logpos{Another row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{a} & \logpos{b} \\ \logpos{Another row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{a} & \logpos{b} \\ \logpos{Another row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{a} & \logpos{b} \\ \logpos{Another row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{a} & \logpos{b} \\ \logpos{row head 2} & \logpos{c} & \logpos{d} \\ asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf & col 1 & col 2 \end{sdapsarray} \end{addmargin} \end{MYTESTPAGE} \begin{MYTESTPAGE}{sdapsarray modifying separation} % The row headers can be multiline and should properly flow as paragraphs. % They are ragged right though towards the cells. colsep=1em,rowsep=1em \begin{sdapsarray}[colsep=1em,rowsep=1em] & col 1 & col 2 \\ \logpos{A row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{a} & \logpos{b} \\ \logpos{Another row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{a} & \logpos{b} \\ \logpos{Another row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{a} & \logpos{b} \\ \logpos{Another row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{a} & \logpos{b} \\ \logpos{Another row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{a} & \logpos{b} \\ \logpos{row head 2} & \logpos{c} & \logpos{d} \\ asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf & col 1 & col 2 \end{sdapsarray} \hrule colsep=1em,rowsep=1em \begin{sdapsarray}[flip,colsep=1em,rowsep=1em] & \logpos{A row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{Another row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{Another row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{Another row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{Another row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. \\ col 1 & \logpos{a} & \logpos{a} & \logpos{a} & \logpos{a} & \logpos{a} \\ col 2 & \logpos{b} & \logpos{b} & \logpos{b} & \logpos{b} & \logpos{b} \end{sdapsarray} \hrule { \vfil \break \lineskiplimit=2ex \lineskip=2ex lineskiplimit=2ex,lineskip=2ex \begin{sdapsarray}[colsep=1em] & col 1 & col 2 \\ \logpos{A row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{a} & \logpos{b} \\ \logpos{Another row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{a} & \logpos{b} \\ \logpos{Another row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{a} & \logpos{b} \\ \logpos{Another row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{a} & \logpos{b} \\ \logpos{Another row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{a} & \logpos{b} \\ \logpos{row head 2} & \logpos{c} & \logpos{d} \\ x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x & col 1 & col 2 \end{sdapsarray} \hrule \lineskiplimit=2ex \lineskip=0ex lineskiplimit=2ex,lineskip=0ex (i.e. effectively no lineskip) \begin{sdapsarray}[flip,colsep=1em] & \logpos{A row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{Another row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{Another row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{Another row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. & \logpos{Another row} header with a lot of text which will wrap over multiple lines. And here comes the \logpos{end of it}. \\ col 1 & \logpos{a} & \logpos{a} & \logpos{a} & \logpos{a} & \logpos{a} \\ col 2 & \logpos{b} & \logpos{b} & \logpos{b} & \logpos{b} & \logpos{b} \end{sdapsarray} } \hrule \end{MYTESTPAGE} \begin{MYTESTPAGE}{sdapsarray with special contents} % \begin{sdapsarray} \logpos{row head} & \logpos{col head 1} & \logpos{col head 2} \\ \logpos{row head 1} & \logpos{a} & \logpos{b} \\ \lognamedpos{verb}\verb^row head 2^ & \sdapsnested{ $\begin{array}{ccc} a & b \\ \logpos{c} & d \end{array}$ } & \logpos{d} \end{sdapsarray} \end{MYTESTPAGE} \begin{MYTESTPAGE}{baseline handling at the top} \begin{multicols}{2} Filler text above baseline. \begin{sdapsarray} {} & \logpos{col 1} & col 2 \\ 2 & a & b \\ 3 & c & d \end{sdapsarray} \logpos{x} \hrule \columnbreak Text going underneath the baseline. \begin{sdapsarray} {} & \logpos{col 1} & col 2 \\ 2 & a & b \\ 3 & c & d \end{sdapsarray} \logpos{x} \hrule \end{multicols} \end{MYTESTPAGE} \begin{MYTESTPAGE}{baseline handling at the bottom} \begin{multicols}{4} \begin{sdapsarray} {} & col 1 & col 2 \\ 2 & a & b \\ 3 & c & d \end{sdapsarray} \logpos{x} \hrule \columnbreak \begin{sdapsarray} {} & col 1 & col 2 \\ 2 & a & b \\ 3 & c & d \end{sdapsarray} \logpos{M} \hrule \columnbreak % The last row contains a g to go below the baseline \begin{sdapsarray} {} & col 1 & col 2 \\ 2 & a & b \\ 3 & c & g \end{sdapsarray} \logpos{x} \hrule \columnbreak % The last row contains a g to go below the baseline \begin{sdapsarray} {} & col 1 & col 2 \\ 2 & a & b \\ 3 & c & g \end{sdapsarray} \logpos{M} \hrule \end{multicols} \end{MYTESTPAGE} \begin{MYTESTPAGE}{baseline handling between rows} % TODO: Compare to normal vbox handling. % NOTE: Also tests handling of the baseline on the same row % (i.e. the row header baseline should not be moved above the cells % baseline) \begin{multicols}{4} \begin{sdapsarray} {} & \logpos{col 1} & col 2 \\ 2 & \logpos{a} & b \\ 3 & \logpos{c} & d \end{sdapsarray} \lognamedpos{rule} x\hrule \columnbreak \begin{sdapsarray} {} & \logpos{col 1} & col 2g \\ 2 & \logpos{a} & b \\ 3 & \logpos{c} & d \end{sdapsarray} \lognamedpos{rule} x\hrule \columnbreak \begin{sdapsarray} {} & \logpos{col 1} & col 2 \\ 2 & \logpos{a} & bg \\ 3 & \logpos{c} & d \end{sdapsarray} \lognamedpos{rule} x\hrule \columnbreak \begin{sdapsarray} {} & \logpos{col 1} & col 2 \\ 2 & \logpos{a} & b \\ 3 & \logpos{c} & dg \end{sdapsarray} \lognamedpos{rule} x\hrule \end{multicols} \begin{multicols}{4} \begin{sdapsarray} {} & \logpos{col 1} & col 2 \\ 2 & \logpos{a} & b \\ 3 & \logpos{c} & d \end{sdapsarray} \lognamedpos{rule} x\hrule \columnbreak \begin{sdapsarray} g & \logpos{col 1} & col 2 \\ 2 & \logpos{a} & b \\ 3 & \logpos{c} & d \end{sdapsarray} \lognamedpos{rule} x\hrule \columnbreak \begin{sdapsarray} {} & \logpos{col 1} & col 2 \\ g & \logpos{a} & b \\ 3 & \logpos{c} & d \end{sdapsarray} \lognamedpos{rule} x\hrule \columnbreak \begin{sdapsarray} {} & \logpos{col 1} & col 2 \\ 2 & \logpos{a} & b \\ g & \logpos{c} & d \end{sdapsarray} \lognamedpos{rule} x\hrule \end{multicols} \begin{multicols}{4} \begin{sdapsarray} {} & \logpos{col 1} & col 2 \\ 2 & \logpos{a} & a \\ 3 & \logpos{c} & a \end{sdapsarray} \lognamedpos{rule} x\hrule \columnbreak \begin{sdapsarray} {} & \logpos{col 1} & col 2 \\ & \logpos{a} & a \\ & \logpos{c} & a \end{sdapsarray} \lognamedpos{rule} x\hrule \columnbreak \begin{sdapsarray} {} & \logpos{col 1} & col 2 \\ & \logpos{a} & a \\ & \logpos{c} & d \end{sdapsarray} \lognamedpos{rule} x\hrule \columnbreak \begin{sdapsarray} {} & \logpos{col 1} & col 2 \\ & \logpos{a} & g \\ & \logpos{c} & d \end{sdapsarray} \lognamedpos{rule} x\hrule \end{multicols} \end{MYTESTPAGE} \begin{MYTESTPAGE}{baselineskip handling at the top} \begin{multicols}{2} Filler text above baseline. \begin{sdapsarray}[] \logpos{row head} & \logpos{col head 1} & \logpos{col head 2} \\ \logpos{row head 2} & \logpos{a} & \logpos{b} \\ \logpos{row head 3} & \logpos{c} & \logpos{d} \end{sdapsarray} \columnbreak Text going underneath the baseline. \begin{sdapsarray}[] \logpos{row head} & \logpos{col head 1} & \logpos{col head 2} \\ \logpos{row head 2} & \logpos{a} & \logpos{b} \\ \logpos{row head 3} & \logpos{c} & \logpos{d} \end{sdapsarray} \end{multicols} \end{MYTESTPAGE} %\TEST{2} % { % blub\logpos % \newpage % } \end{document} sdaps-1.9.8/tex/class/testfiles/array.tlg0000644000175000000660000004130413416727013021142 0ustar benjaminlock00000000000000This is a generated file for the l3build validation system. Don't change this file in any respect. ============================================================ TEST 1: Basic alignment and layout ============================================================ [2 POSITION row head: 22087078,49122001 POSITION col head 1: 25726048,49122001 POSITION col head 2: 29701901,49122001 POSITION row head 2: 21489062,48230711 POSITION a: 27141354,48230711 POSITION b: 31097273,48230711 POSITION row head 3: 21489062,47339421 POSITION c: 27161288,47339421 POSITION d: 31097273,47339421 POSITION a: 27141354,46814861 POSITION b: 31097273,46814861 POSITION aligned head: 20992706,45923571 POSITION c: 27161288,45923571 POSITION d: 31097273,45923571 POSITION e: 31367336,45259474 POSITION f: 32582347,45259474 POSITION unaligned head: 25816704,44368184 POSITION g: 31347402,44368184 POSITION h: 32492644,44368184 ] ============================================================ ============================================================ TEST 2: Spaces in cells are not relevant ============================================================ [3 POSITION a: 31347402,49122001 POSITION b: 32492644,49122001 POSITION d: 32492644,48230711 POSITION a: 31347402,47339421 POSITION b: 32492644,47339421 POSITION d: 32492644,46448131 POSITION a: 31347402,44665551 POSITION b: 31307534,43774261 POSITION d: 32492644,43774261 POSITION a: 31347402,41991681 POSITION b: 31307534,41100391 POSITION d: 32492644,41100391 ] ============================================================ ============================================================ TEST 3: Cells can be right/left aligned using hfill/vfill ============================================================ [4 POSITION column: 27559962,49122001 POSITION column: 30618858,49122001 POSITION x: 29453681,48230711 POSITION x: 32512577,48230711 POSITION x: 28506822,47339421 POSITION x: 31565718,47339421 POSITION x: 27559962,46448131 POSITION x: 30618858,46448131 POSITION x: 29453681,45556841 POSITION x: 32512577,45556841 POSITION x: 28506822,44665551 POSITION x: 31565718,44665551 POSITION x: 27559962,43774261 POSITION x: 30618858,43774261 POSITION column: 17049618,41991681 POSITION x: 21204877,41991681 POSITION x: 22918236,41991681 POSITION x: 24631594,41991681 POSITION x: 27989497,41991681 POSITION x: 29702856,41991681 POSITION x: 31416214,41991681 POSITION column: 17049618,41100391 POSITION x: 21204877,41100391 POSITION x: 22918236,41100391 POSITION x: 24631594,41100391 POSITION x: 27989497,41100391 POSITION x: 29702856,41100391 POSITION x: 31416214,41100391 ] ============================================================ ============================================================ TEST 4: Fliptest ============================================================ [5 POSITION row head: 21564812,49122001 POSITION col head 1: 25334349,49122001 POSITION col head 2: 29571335,49122001 POSITION row head 2: 20966796,48230711 POSITION a: 26749654,48230711 POSITION b: 30966706,48230711 POSITION row head 3: 20966796,47339421 POSITION c: 26769588,47339421 POSITION d: 30966706,47339421 POSITION row head: 21564812,46814861 POSITION row head 2: 25203782,46814861 POSITION row head 3: 29440768,46814861 POSITION col head 1: 21227929,45923571 POSITION a: 26749654,45923571 POSITION c: 31006574,45923571 POSITION col head 2: 21227929,45032281 POSITION b: 26729720,45032281 POSITION d: 30966706,45032281 ] ============================================================ ============================================================ TEST 5: sdapsarray spanning a multicol environment ============================================================ [6 POSITION row head: 8027786,48407655 POSITION col head 1: 11692970,48407655 POSITION col head 2: 15668823,48407655 POSITION row head 1: 7455984,47126152 POSITION a: 13108276,47126152 POSITION b: 17064195,47126152 POSITION row head 2: 7190564,45625374 POSITION c: 13128210,45625374 POSITION d: 17064195,45625374 POSITION row head 3: 7455984,44343871 POSITION e: 13128210,44343871 POSITION f: 17153897,44343871 POSITION row head: 22060864,48407655 POSITION col head 1: 25726048,48407655 POSITION col head 2: 29701901,48407655 POSITION row head 4: 21489062,47126152 POSITION g: 27141354,47126152 POSITION h: 31097273,47126152 POSITION row head 5: 21489062,46234862 POSITION i: 27221089,46234862 POSITION j: 31186975,46234862 POSITION row head 6: 21489062,45343572 POSITION k: 27131386,45343572 POSITION l: 31196942,45343572 POSITION row head 7: 21489062,44452282 POSITION m: 27021750,44452282 POSITION n: 31097273,44452282 ] ============================================================ ============================================================ TEST 6: sdapsarray not splitting with huge penalty ============================================================ [7 POSITION a: 17941286,48230711 POSITION a: 17941286,31296201 ] ============================================================ ============================================================ TEST 7: sdapsarray should discourage being split over pages ============================================================ [8] [9 POSITION a: 31974364,48230711 POSITION a: 31974364,40209101 ] ============================================================ ============================================================ TEST 8: sdapsarray with rotated header ============================================================ [10 POSITION row head: 21321661,44321469 POSITION col head 1: 26676530,44321469 POSITION col head 2: 30271214,44321469 POSITION row head 1: 20723645,43133053 POSITION a: 26497127,43133053 POSITION b: 30071879,43133053 POSITION row head 2: 20723645,42241763 POSITION c: 26517061,42241763 POSITION d: 30071879,42241763 POSITION row head 3: 20723645,41350473 POSITION e: 26517061,41350473 POSITION f: 30161582,41350473 POSITION row head: 24984363,38508148 POSITION col head 1: 28975717,38508148 POSITION col head 2: 30466917,38508148 POSITION row head 1: 24386347,37616858 POSITION a: 28796312,37616858 POSITION b: 30267578,37616858 POSITION row head 2: 24386347,36725568 POSITION c: 28816246,36725568 POSITION d: 30267578,36725568 POSITION row head 3: 24386347,35834278 POSITION e: 28816246,35834278 POSITION f: 30357281,35834278 ] ============================================================ ============================================================ TEST 9: sdapsarray with rotated header ============================================================ [11 POSITION row head: 23520341,46450597 POSITION col head 1: 27627603,46450597 POSITION col head 2: 29350623,46450597 POSITION row head 1: 22922325,45559307 POSITION a: 27448200,45559307 POSITION b: 29151286,45559307 POSITION row head 2: 22922325,44668017 POSITION c: 27468134,44668017 POSITION d: 29151286,44668017 POSITION row head 3: 22922325,43776727 POSITION e: 27468134,43776727 POSITION f: 29240989,43776727 POSITION row head: 23520341,34173009 POSITION col head 1: 27627603,34173009 POSITION col head 2 with extra long text: 29350623,34173009 POSITION row head 1: 22922325,33281719 POSITION a: 27448200,33281719 POSITION b: 29151286,33281719 POSITION row head 2: 22922325,32390429 POSITION c: 27468134,32390429 POSITION d: 29151286,32390429 POSITION row head 3: 22922325,31499139 POSITION e: 27468134,31499139 POSITION f: 29240989,31499139 ] ============================================================ ============================================================ TEST 10: sdapsarray with multiline row header ============================================================ [12 POSITION A row: 7126699,48230711 POSITION end of it: 25517698,47339421 POSITION a: 29712825,47785066 POSITION b: 31954430,47785066 POSITION Another row: 6929352,46448131 POSITION end of it: 25517698,45556841 POSITION a: 29712825,46002486 POSITION b: 31954430,46002486 POSITION Another row: 6929352,44665551 POSITION end of it: 25517698,43774261 POSITION a: 29712825,44219906 POSITION b: 31954430,44219906 POSITION Another row: 6929352,42882971 POSITION end of it: 25517698,41991681 POSITION a: 29712825,42437326 POSITION b: 31954430,42437326 POSITION Another row: 6929352,41100391 POSITION end of it: 25517698,40209101 POSITION a: 29712825,40654746 POSITION b: 31954430,40654746 POSITION row head 2: 24917690,39317811 POSITION c: 29732759,39317811 POSITION d: 31954430,39317811 POSITION A row: 7126699,35228091 POSITION end of it: 25517698,34336801 POSITION a: 29712825,34782446 POSITION b: 31954430,34782446 POSITION Another row: 6929352,33445511 POSITION end of it: 25517698,32554221 POSITION a: 29712825,32999866 POSITION b: 31954430,32999866 POSITION Another row: 6929352,31662931 POSITION end of it: 25517698,30771641 POSITION a: 29712825,31217286 POSITION b: 31954430,31217286 POSITION Another row: 6929352,29880351 POSITION end of it: 25517698,28989061 POSITION a: 29712825,29434706 POSITION b: 31954430,29434706 POSITION Another row: 6929352,28097771 POSITION end of it: 25517698,27206481 POSITION a: 29712825,27652126 POSITION b: 31954430,27652126 ] ============================================================ ============================================================ TEST 11: sdapsarray inside an addmargin environment ============================================================ [13 POSITION A row: 9855063,48230711 POSITION end of it: 22846552,47339421 POSITION a: 26124720,47339421 POSITION b: 28366325,47339421 POSITION Another row: 10840373,45556841 POSITION end of it: 21929593,43774261 POSITION a: 26124720,44665551 POSITION b: 28366325,44665551 POSITION Another row: 10840373,42882971 POSITION end of it: 21929593,41100391 POSITION a: 26124720,41991681 POSITION b: 28366325,41991681 POSITION Another row: 10840373,40209101 POSITION end of it: 21929593,38426521 POSITION a: 26124720,39317811 POSITION b: 28366325,39317811 POSITION Another row: 10840373,37535231 POSITION end of it: 21929593,35752651 POSITION a: 26124720,36643941 POSITION b: 28366325,36643941 POSITION row head 2: 21329585,34861361 POSITION c: 26144654,34861361 POSITION d: 28366325,34861361 ] ============================================================ ============================================================ TEST 12: sdapsarray modifying separation ============================================================ [14 POSITION A row: 7342578,46621800 POSITION end of it: 23895673,45730510 POSITION a: 28739610,46176155 POSITION b: 31630025,46176155 POSITION Another row: 8118005,44121599 POSITION end of it: 23895673,43230309 POSITION a: 28739610,43606186 POSITION b: 31630025,43606186 POSITION Another row: 8118005,41621398 POSITION end of it: 23895673,40730108 POSITION a: 28739610,41105985 POSITION b: 31630025,41105985 POSITION Another row: 8118005,39121197 POSITION end of it: 23895673,38229907 POSITION a: 28739610,38605784 POSITION b: 31630025,38605784 POSITION Another row: 8118005,36620996 POSITION end of it: 23895673,35729706 POSITION a: 28739610,36105583 POSITION b: 31630025,36105583 POSITION row head 2: 23295665,34120795 POSITION c: 28759544,34120795 POSITION d: 31630025,34120795 POSITION A row: 7342578,28595833 POSITION end of it: 23895673,27704543 POSITION a: 28739610,28150188 POSITION b: 31630025,28150188 POSITION Another row: 8118005,26095632 POSITION end of it: 23895673,25204342 POSITION a: 28739610,25580219 POSITION b: 31630025,25580219 POSITION Another row: 8118005,23595431 POSITION end of it: 23895673,22704141 POSITION a: 28739610,23080018 POSITION b: 31630025,23080018 POSITION Another row: 8118005,21095230 POSITION end of it: 23895673,20203940 POSITION a: 28739610,20579817 POSITION b: 31630025,20579817 POSITION Another row: 8118005,18595029 POSITION end of it: 23895673,17703739 POSITION a: 28739610,18079616 POSITION b: 31630025,18079616 ] [15 POSITION A row: 7342578,46749876 POSITION end of it: 23895673,45494045 POSITION a: 28739610,46121961 POSITION b: 31630025,46121961 POSITION Another row: 8118005,44377751 POSITION end of it: 23895673,43121920 POSITION a: 28739610,43680067 POSITION b: 31630025,43680067 POSITION Another row: 8118005,41866089 POSITION end of it: 23895673,40610258 POSITION a: 28739610,41168405 POSITION b: 31630025,41168405 POSITION Another row: 8118005,39354427 POSITION end of it: 23895673,38098596 POSITION a: 28739610,38656743 POSITION b: 31630025,38656743 POSITION Another row: 8118005,36842765 POSITION end of it: 23895673,35586934 POSITION a: 28739610,36145081 POSITION b: 31630025,36145081 POSITION row head 2: 23295665,34331103 POSITION c: 28759544,34331103 POSITION d: 31630025,34331103 POSITION A row: 7342578,30736735 POSITION end of it: 23895673,30098852 POSITION a: 28739610,30417794 POSITION b: 31630025,30417794 POSITION Another row: 8118005,29600506 POSITION end of it: 23895673,28962623 POSITION a: 28739610,29211796 POSITION b: 31630025,29211796 POSITION Another row: 8118005,28324740 POSITION end of it: 23895673,27686857 POSITION a: 28739610,27936030 POSITION b: 31630025,27936030 POSITION Another row: 8118005,27048974 POSITION end of it: 23895673,26411091 POSITION a: 28739610,26660264 POSITION b: 31630025,26660264 POSITION Another row: 8118005,25773208 POSITION end of it: 23895673,25135325 POSITION a: 28739610,25384498 POSITION b: 31630025,25384498 ] ============================================================ ============================================================ TEST 13: sdapsarray with special contents ============================================================ [16 POSITION row head: 22087078,49122001 POSITION col head 1: 25726048,49122001 POSITION col head 2: 29701901,49122001 POSITION row head 1: 21489062,48230711 POSITION a: 27141354,48230711 POSITION b: 31097273,48230711 POSITION verb: 21172156,47094482 POSITION c: 26651046,46649986 POSITION d: 31097273,47094482 ] ============================================================ ============================================================ TEST 14: baseline handling at the top ============================================================ [17 POSITION col 1: 15121598,48230711 POSITION x: 6591363,45556841 POSITION col 1: 29154676,48230711 POSITION x: 20624441,45556841 ] ============================================================ ============================================================ TEST 15: baseline handling at the bottom ============================================================ [18 POSITION x: 6591363,46448131 POSITION M: 13607902,46448131 POSITION x: 20624441,46448131 POSITION M: 27640980,46448131 ] ============================================================ ============================================================ TEST 16: baseline handling between rows ============================================================ [19 POSITION col 1: 8105059,49122001 POSITION a: 8663208,48230711 POSITION c: 8683142,47339421 POSITION rule: 6591363,46448131 POSITION col 1: 14762788,49122001 POSITION a: 15320937,48230711 POSITION c: 15340871,47339421 POSITION rule: 13607902,46448131 POSITION col 1: 22138137,49122001 POSITION a: 22696286,48230711 POSITION c: 22716220,47339421 POSITION rule: 20624441,46448131 POSITION col 1: 29154676,49122001 POSITION a: 29712825,48230711 POSITION c: 29732759,47339421 POSITION rule: 27640980,46448131 POSITION col 1: 8105059,44744195 POSITION a: 8663208,43852905 POSITION c: 8683142,42961615 POSITION rule: 6591363,42070325 POSITION col 1: 15121598,44744195 POSITION a: 15679747,43852905 POSITION c: 15699681,42961615 POSITION rule: 13607902,42070325 POSITION col 1: 22138137,44744195 POSITION a: 22696286,43852905 POSITION c: 22716220,42961615 POSITION rule: 20624441,42070325 POSITION col 1: 29154676,44744195 POSITION a: 29712825,43852905 POSITION c: 29732759,42961615 POSITION rule: 27640980,42070325 POSITION col 1: 8105059,40366389 POSITION a: 8663208,39475099 POSITION c: 8683142,38583809 POSITION rule: 6591363,37692519 POSITION col 1: 15121598,40366389 POSITION a: 15679747,39475099 POSITION c: 15699681,38583809 POSITION rule: 13607902,37692519 POSITION col 1: 22138137,40366389 POSITION a: 22696286,39475099 POSITION c: 22716220,38583809 POSITION rule: 20624441,37692519 POSITION col 1: 29154676,40366389 POSITION a: 29712825,39475099 POSITION c: 29732759,38583809 POSITION rule: 27640980,37692519 ] ============================================================ ============================================================ TEST 17: baselineskip handling at the top ============================================================ [20 POSITION row head: 8054000,48230711 POSITION col head 1: 11692970,48230711 POSITION col head 2: 15668823,48230711 POSITION row head 2: 7455984,47339421 POSITION a: 13108276,47339421 POSITION b: 17064195,47339421 POSITION row head 3: 7455984,46448131 POSITION c: 13128210,46448131 POSITION d: 17064195,46448131 POSITION row head: 22087078,48230711 POSITION col head 1: 25726048,48230711 POSITION col head 2: 29701901,48230711 POSITION row head 2: 21489062,47339421 POSITION a: 27141354,47339421 POSITION b: 31097273,47339421 POSITION row head 3: 21489062,46448131 POSITION c: 27161288,46448131 POSITION d: 31097273,46448131 ] ============================================================ (array.aux) sdaps-1.9.8/tex/class/testfiles/array.xetex.tlg0000644000175000000660000004130413416727013022276 0ustar benjaminlock00000000000000This is a generated file for the l3build validation system. Don't change this file in any respect. ============================================================ TEST 1: Basic alignment and layout ============================================================ [2 POSITION row head: 22087724,49122001 POSITION col head 1: 25726692,49122001 POSITION col head 2: 29702223,49122001 POSITION row head 2: 21489947,48230711 POSITION a: 27141837,48230711 POSITION b: 31097275,48230711 POSITION row head 3: 21489947,47339421 POSITION c: 27161930,47339421 POSITION d: 31097275,47339421 POSITION a: 27141837,46799392 POSITION b: 31097275,46799392 POSITION aligned head: 20992638,45908102 POSITION c: 27161930,45908102 POSITION d: 31097275,45908102 POSITION e: 31367178,45228138 POSITION f: 32582029,45228138 POSITION unaligned head: 25815037,44336848 POSITION g: 31347084,44336848 POSITION h: 32492326,44336848 ] ============================================================ ============================================================ TEST 2: Spaces in cells are not relevant ============================================================ [3 POSITION a: 31347084,49122001 POSITION b: 32492326,49122001 POSITION d: 32492326,48230711 POSITION a: 31347084,47339421 POSITION b: 32492326,47339421 POSITION d: 32492326,46448131 POSITION a: 31347084,44665551 POSITION b: 31306898,43774261 POSITION d: 32492326,43774261 POSITION a: 31347084,41991681 POSITION b: 31306898,41100391 POSITION d: 32492326,41100391 ] ============================================================ ============================================================ TEST 3: Cells can be right/left aligned using hfill/vfill ============================================================ [4 POSITION column: 27559490,49122001 POSITION column: 30618622,49122001 POSITION x: 29453287,48230711 POSITION x: 32512419,48230711 POSITION x: 28506389,47339421 POSITION x: 31565521,47339421 POSITION x: 27559490,46448131 POSITION x: 30618622,46448131 POSITION x: 29453287,45556841 POSITION x: 32512419,45556841 POSITION x: 28506389,44665551 POSITION x: 31565521,44665551 POSITION x: 27559490,43774261 POSITION x: 30618622,43774261 POSITION column: 17047480,41991681 POSITION x: 21203134,41991681 POSITION x: 22916730,41991681 POSITION x: 24630326,41991681 POSITION x: 27988705,41991681 POSITION x: 29702301,41991681 POSITION x: 31415897,41991681 POSITION column: 17047480,41100391 POSITION x: 21203134,41100391 POSITION x: 22916730,41100391 POSITION x: 24630326,41100391 POSITION x: 27988705,41100391 POSITION x: 29702301,41100391 POSITION x: 31415897,41100391 ] ============================================================ ============================================================ TEST 4: Fliptest ============================================================ [5 POSITION row head: 21565296,49122001 POSITION col head 1: 25334871,49122001 POSITION col head 2: 29571616,49122001 POSITION row head 2: 20967519,48230711 POSITION a: 26750016,48230711 POSITION b: 30966668,48230711 POSITION row head 3: 20967519,47339421 POSITION c: 26770109,47339421 POSITION d: 30966668,47339421 POSITION row head: 21565296,46799392 POSITION row head 2: 25204264,46799392 POSITION row head 3: 29441009,46799392 POSITION col head 1: 21228733,45908102 POSITION a: 26750016,45908102 POSITION c: 31006854,45908102 POSITION col head 2: 21228733,45016812 POSITION b: 26729923,45016812 POSITION d: 30966668,45016812 ] ============================================================ ============================================================ TEST 5: sdapsarray spanning a multicol environment ============================================================ [6 POSITION row head: 8028432,48407659 POSITION col head 1: 11693614,48407659 POSITION col head 2: 15669145,48407659 POSITION row head 1: 7456869,47126476 POSITION a: 13108759,47126476 POSITION b: 17064197,47126476 POSITION row head 2: 7191688,45617809 POSITION c: 13128852,45617809 POSITION d: 17064197,45617809 POSITION row head 3: 7456869,44328733 POSITION e: 13128852,44328733 POSITION f: 17153899,44328733 POSITION row head: 22061510,48407659 POSITION col head 1: 25726692,48407659 POSITION col head 2: 29702223,48407659 POSITION row head 4: 21489947,47126476 POSITION g: 27141837,47126476 POSITION h: 31097275,47126476 POSITION row head 5: 21489947,46235186 POSITION i: 27221493,46235186 POSITION j: 31186977,46235186 POSITION row head 6: 21489947,45343896 POSITION k: 27131790,45343896 POSITION l: 31197024,45343896 POSITION row head 7: 21489947,44452606 POSITION m: 27022353,44452606 POSITION n: 31097275,44452606 ] ============================================================ ============================================================ TEST 6: sdapsarray not splitting with huge penalty ============================================================ [7 POSITION a: 17941486,48230711 POSITION a: 17941486,31296201 ] ============================================================ ============================================================ TEST 7: sdapsarray should discourage being split over pages ============================================================ [8] [9 POSITION a: 31974564,48230711 POSITION a: 31974564,40209101 ] ============================================================ ============================================================ TEST 8: sdapsarray with rotated header ============================================================ [10 POSITION row head: 21321745,44321693 POSITION col head 1: 26676612,44321693 POSITION col head 2: 30271296,44321693 POSITION row head 1: 20723968,43133595 POSITION a: 26497209,43133595 POSITION b: 30071802,43133595 POSITION row head 2: 20723968,42242305 POSITION c: 26517303,42242305 POSITION d: 30071802,42242305 POSITION row head 3: 20723968,41351015 POSITION e: 26517303,41351015 POSITION f: 30161505,41351015 POSITION row head: 24979855,38493524 POSITION col head 1: 28970982,38493524 POSITION col head 2: 30461732,38493524 POSITION row head 1: 24382078,37602234 POSITION a: 28791577,37602234 POSITION b: 30262234,37602234 POSITION row head 2: 24382078,36710944 POSITION c: 28811671,36710944 POSITION d: 30262234,36710944 POSITION row head 3: 24382078,35819654 POSITION e: 28811671,35819654 POSITION f: 30351937,35819654 ] ============================================================ ============================================================ TEST 9: sdapsarray with rotated header ============================================================ [11 POSITION row head: 23513616,46451233 POSITION col head 1: 27620577,46451233 POSITION col head 2: 29342999,46451233 POSITION row head 1: 22915839,45559943 POSITION a: 27441174,45559943 POSITION b: 29143503,45559943 POSITION row head 2: 22915839,44668653 POSITION c: 27461268,44668653 POSITION d: 29143503,44668653 POSITION row head 3: 22915839,43777363 POSITION e: 27461268,43777363 POSITION f: 29233206,43777363 POSITION row head: 23513616,34158430 POSITION col head 1: 27620577,34158430 POSITION col head 2 with extra long text: 29342999,34158430 POSITION row head 1: 22915839,33267140 POSITION a: 27441174,33267140 POSITION b: 29143503,33267140 POSITION row head 2: 22915839,32375850 POSITION c: 27461268,32375850 POSITION d: 29143503,32375850 POSITION row head 3: 22915839,31484560 POSITION e: 27461268,31484560 POSITION f: 29233206,31484560 ] ============================================================ ============================================================ TEST 10: sdapsarray with multiline row header ============================================================ [12 POSITION A row: 7128241,48230711 POSITION end of it: 25517944,47339421 POSITION a: 29713425,47792959 POSITION b: 31954471,47792959 POSITION Another row: 6930177,46448131 POSITION end of it: 25517944,45556841 POSITION a: 29713425,46010379 POSITION b: 31954471,46010379 POSITION Another row: 6930177,44665551 POSITION end of it: 25517944,43774261 POSITION a: 29713425,44227799 POSITION b: 31954471,44227799 POSITION Another row: 6930177,42882971 POSITION end of it: 25517944,41991681 POSITION a: 29713425,42445219 POSITION b: 31954471,42445219 POSITION Another row: 6930177,41100391 POSITION end of it: 25517944,40209101 POSITION a: 29713425,40662639 POSITION b: 31954471,40662639 POSITION row head 2: 24918731,39317811 POSITION c: 29733518,39317811 POSITION d: 31954471,39317811 POSITION A row: 7128241,35228409 POSITION end of it: 25517944,34337119 POSITION a: 29713425,34790657 POSITION b: 31954471,34790657 POSITION Another row: 6930177,33445829 POSITION end of it: 25517944,32554539 POSITION a: 29713425,33008077 POSITION b: 31954471,33008077 POSITION Another row: 6930177,31663249 POSITION end of it: 25517944,30771959 POSITION a: 29713425,31225497 POSITION b: 31954471,31225497 POSITION Another row: 6930177,29880669 POSITION end of it: 25517944,28989379 POSITION a: 29713425,29442917 POSITION b: 31954471,29442917 POSITION Another row: 6930177,28098089 POSITION end of it: 25517944,27206799 POSITION a: 29713425,27660337 POSITION b: 31954471,27660337 ] ============================================================ ============================================================ TEST 11: sdapsarray inside an addmargin environment ============================================================ [13 POSITION A row: 9855053,48230711 POSITION end of it: 22846966,47339421 POSITION a: 26125330,47347314 POSITION b: 28366376,47347314 POSITION Another row: 10841200,45556841 POSITION end of it: 21929849,43774261 POSITION a: 26125330,44673444 POSITION b: 28366376,44673444 POSITION Another row: 10841200,42882971 POSITION end of it: 21929849,41100391 POSITION a: 26125330,41999574 POSITION b: 28366376,41999574 POSITION Another row: 10841200,40209101 POSITION end of it: 21929849,38426521 POSITION a: 26125330,39325704 POSITION b: 28366376,39325704 POSITION Another row: 10841200,37535231 POSITION end of it: 21929849,35752651 POSITION a: 26125330,36651834 POSITION b: 28366376,36651834 POSITION row head 2: 21330636,34861361 POSITION c: 26145423,34861361 POSITION d: 28366376,34861361 ] ============================================================ ============================================================ TEST 12: sdapsarray modifying separation ============================================================ [14 POSITION A row: 7344048,46621802 POSITION end of it: 23895929,45730512 POSITION a: 28740216,46184050 POSITION b: 31630068,46184050 POSITION Another row: 8119076,44121603 POSITION end of it: 23895929,43230313 POSITION a: 28740216,43618189 POSITION b: 31630068,43618189 POSITION Another row: 8119076,41621404 POSITION end of it: 23895929,40730114 POSITION a: 28740216,41117990 POSITION b: 31630068,41117990 POSITION Another row: 8119076,39121205 POSITION end of it: 23895929,38229915 POSITION a: 28740216,38617791 POSITION b: 31630068,38617791 POSITION Another row: 8119076,36621006 POSITION end of it: 23895929,35729716 POSITION a: 28740216,36117592 POSITION b: 31630068,36117592 POSITION row head 2: 23296716,34120807 POSITION c: 28760309,34120807 POSITION d: 31630068,34120807 POSITION A row: 7344048,28588274 POSITION end of it: 23895929,27696984 POSITION a: 28740216,28150522 POSITION b: 31630068,28150522 POSITION Another row: 8119076,26088075 POSITION end of it: 23895929,25196785 POSITION a: 28740216,25584661 POSITION b: 31630068,25584661 POSITION Another row: 8119076,23587876 POSITION end of it: 23895929,22696586 POSITION a: 28740216,23084462 POSITION b: 31630068,23084462 POSITION Another row: 8119076,21087677 POSITION end of it: 23895929,20196387 POSITION a: 28740216,20584263 POSITION b: 31630068,20584263 POSITION Another row: 8119076,18587478 POSITION end of it: 23895929,17696188 POSITION a: 28740216,18084064 POSITION b: 31630068,18084064 ] [15 POSITION A row: 7344048,46725872 POSITION end of it: 23895929,45454252 POSITION a: 28740216,46097955 POSITION b: 31630068,46097955 POSITION Another row: 8119076,44313956 POSITION end of it: 23895929,43042336 POSITION a: 28740216,43620377 POSITION b: 31630068,43620377 POSITION Another row: 8119076,41770716 POSITION end of it: 23895929,40499096 POSITION a: 28740216,41077137 POSITION b: 31630068,41077137 POSITION Another row: 8119076,39227476 POSITION end of it: 23895929,37955856 POSITION a: 28740216,38533897 POSITION b: 31630068,38533897 POSITION Another row: 8119076,36684236 POSITION end of it: 23895929,35412616 POSITION a: 28740216,35990657 POSITION b: 31630068,35990657 POSITION row head 2: 23296716,34156783 POSITION c: 28760309,34156783 POSITION d: 31630068,34156783 POSITION A row: 7344048,30529558 POSITION end of it: 23895929,29876526 POSITION a: 28740216,30210935 POSITION b: 31630068,30210935 POSITION Another row: 8119076,29354818 POSITION end of it: 23895929,28701786 POSITION a: 28740216,28970533 POSITION b: 31630068,28970533 POSITION Another row: 8119076,28048754 POSITION end of it: 23895929,27395722 POSITION a: 28740216,27664469 POSITION b: 31630068,27664469 POSITION Another row: 8119076,26742690 POSITION end of it: 23895929,26089658 POSITION a: 28740216,26358405 POSITION b: 31630068,26358405 POSITION Another row: 8119076,25436626 POSITION end of it: 23895929,24783594 POSITION a: 28740216,25052341 POSITION b: 31630068,25052341 ] ============================================================ ============================================================ TEST 13: sdapsarray with special contents ============================================================ [16 POSITION row head: 22087724,49122001 POSITION col head 1: 25726692,49122001 POSITION col head 2: 29702223,49122001 POSITION row head 1: 21489947,48230711 POSITION a: 27141837,48230711 POSITION b: 31097275,48230711 POSITION verb: 21172760,47086589 POSITION c: 26651529,46642093 POSITION d: 31097275,47086589 ] ============================================================ ============================================================ TEST 14: baseline handling at the top ============================================================ [17 POSITION col 1: 15122398,48230711 POSITION x: 6591361,45556841 POSITION col 1: 29155476,48230711 POSITION x: 20624439,45556841 ] ============================================================ ============================================================ TEST 15: baseline handling at the bottom ============================================================ [18 POSITION x: 6591361,46448131 POSITION M: 13607900,46448131 POSITION x: 20624439,46448131 POSITION M: 27640978,46448131 ] ============================================================ ============================================================ TEST 16: baseline handling between rows ============================================================ [19 POSITION col 1: 8105859,49122001 POSITION a: 8663808,48230711 POSITION c: 8683901,47339421 POSITION rule: 6591361,46448131 POSITION col 1: 14763589,49122001 POSITION a: 15321538,48230711 POSITION c: 15341631,47339421 POSITION rule: 13607900,46448131 POSITION col 1: 22138937,49122001 POSITION a: 22696886,48230711 POSITION c: 22716979,47339421 POSITION rule: 20624439,46448131 POSITION col 1: 29155476,49122001 POSITION a: 29713425,48230711 POSITION c: 29733518,47339421 POSITION rule: 27640978,46448131 POSITION col 1: 8105859,44744195 POSITION a: 8663808,43852905 POSITION c: 8683901,42961615 POSITION rule: 6591361,42070325 POSITION col 1: 15122398,44744195 POSITION a: 15680347,43852905 POSITION c: 15700440,42961615 POSITION rule: 13607900,42070325 POSITION col 1: 22138937,44744195 POSITION a: 22696886,43852905 POSITION c: 22716979,42961615 POSITION rule: 20624439,42070325 POSITION col 1: 29155476,44744195 POSITION a: 29713425,43852905 POSITION c: 29733518,42961615 POSITION rule: 27640978,42070325 POSITION col 1: 8105859,40366389 POSITION a: 8663808,39475099 POSITION c: 8683901,38583809 POSITION rule: 6591361,37692519 POSITION col 1: 15122398,40366389 POSITION a: 15680347,39475099 POSITION c: 15700440,38583809 POSITION rule: 13607900,37692519 POSITION col 1: 22138937,40366389 POSITION a: 22696886,39475099 POSITION c: 22716979,38583809 POSITION rule: 20624439,37692519 POSITION col 1: 29155476,40366389 POSITION a: 29713425,39475099 POSITION c: 29733518,38583809 POSITION rule: 27640978,37692519 ] ============================================================ ============================================================ TEST 17: baselineskip handling at the top ============================================================ [20 POSITION row head: 8054646,48230711 POSITION col head 1: 11693614,48230711 POSITION col head 2: 15669145,48230711 POSITION row head 2: 7456869,47339421 POSITION a: 13108759,47339421 POSITION b: 17064197,47339421 POSITION row head 3: 7456869,46448131 POSITION c: 13128852,46448131 POSITION d: 17064197,46448131 POSITION row head: 22087724,48230711 POSITION col head 1: 25726692,48230711 POSITION col head 2: 29702223,48230711 POSITION row head 2: 21489947,47339421 POSITION a: 27141837,47339421 POSITION b: 31097275,47339421 POSITION row head 3: 21489947,46448131 POSITION c: 27161930,46448131 POSITION d: 31097275,46448131 ] ============================================================ (array.aux) sdaps-1.9.8/tex/class/testfiles/base-textboxes.lvt0000644000175000000660000001725113255764711023013 0ustar benjaminlock00000000000000\documentclass{scrartcl} \input{regression-test} \OMIT \usepackage{sdapsbase} \usepackage{multicol} \def\logpos#1{\lognamedpos{#1}#1} \def\lognamedpos#1{\pdfsavepos\write128{POSITION #1: \the\pdflastxpos,\the\pdflastypos}} \newenvironment{MYTEST}[1]{% \begingroup% \global\advance \gTESTint 1 % \SEPARATOR% \LONGTYPEOUT{% TEST \the\gTESTint: \detokenize{#1}}% \SEPARATOR% }{% \SEPARATOR% \LONGTYPEOUT{}% \endgroup% } \newenvironment{OMITPAGE}{% \begingroup% \OMIT% }{% \vfil\break% \TIMO% \endgroup% } \newenvironment{MYTESTPAGE}[1]{% \begin{MYTEST}{#1}% }{% \vfil\break% \end{MYTEST}% } \newenvironment{MYTESTPAGESHOW}[1]{% \begin{MYTESTPAGE}{#1}% \showoutput% }{% \end{MYTESTPAGE}% } \TIMO \begin{document} \START \begin{OMITPAGE} % Some font stuff $ a + b $ % Enable writing out information. \ExplSyntaxOn % Redirect output to log file instead of .sdaps file \iow_close:N \g_sdaps_infofile_iow \global\let\g_sdaps_infofile_iow=\c_log_iow \sdaps_begin: \sdaps_context_enable_writing: \ExplSyntaxOff \textbackslash \end{OMITPAGE} \begin{MYTESTPAGESHOW}{hstretch: visually check the outline does not overshoot} \thispagestyle{empty} \ExplSyntaxOn % Reset counting \int_gzero:N \g__sdaps_object_id_int \sdaps_qobject_begin:nn {Text} { } \noindent\sdaps_textbox_hstretch:nnnnn{ text }{2mm}{5mm}{70mm}{1} \newline \vrule height 1em \hfill \vrule height 1em \newline \noindent \rlap{\vrule depth 4mm}\sdaps_textbox_hstretch:nnnnn{ text }{2mm}{5mm}{70mm}{0}\llap{\vrule depth 4mm}\lognamedpos{at70mm}\, \vrule height 5mm depth 2mm width 2pt \newline \rlap{\vrule height 1em} \hspace{70mm} \llap{\vrule height 1em} \sdaps_qobject_end: \ExplSyntaxOff \end{MYTESTPAGESHOW} \begin{MYTESTPAGE}{hstretch: check only specified width is used} \ExplSyntaxOn % Reset counting \int_gzero:N \g__sdaps_object_id_int \sdaps_qobject_begin:nn {Text} { } \noindent \hfill \lognamedpos{center1} \sdaps_textbox_hstretch:nnnnn{ text }{2mm}{5mm}{0mm}{1} \newline \noindent \sdaps_textbox_hstretch:nnnnn{ text }{2mm}{5mm}{0mm}{1} \lognamedpos{center2} \hfill \strut \sdaps_qobject_end: \ExplSyntaxOff \end{MYTESTPAGE} \begin{MYTESTPAGE}{hbox: check alignment} \ExplSyntaxOn % Reset counting \int_gzero:N \g__sdaps_object_id_int \sdaps_qobject_begin:nn {Text} { } \noindent\sdaps_textbox_hbox:nnn {text} {3bp} { x } \rule{5cm}{.5pt} \hfill \rule{5cm}{.5pt} \sdaps_textbox_hbox:nnn {text} {1bp} { Xg } \newline \vrule height 1em ~2bp~between~content~and~outline \hfill 0bp~between~content~and~outline~ \vrule height 1em \sdaps_qobject_end: \ExplSyntaxOff \end{MYTESTPAGE} \begin{MYTESTPAGE}{hbox: inside a formular} \ExplSyntaxOn % Reset counting \int_gzero:N \g__sdaps_object_id_int \sdaps_qobject_begin:nn {Text} { } \noindent Inside ~ a ~ formula ~ $ f(x) = \frac{1}{c\,\sdaps_textbox_hbox:nnn{text}{3bp}{box}} \sdaps_textbox_hstretch:nnnnn{text}{2mm}{5mm}{70mm}{1} $ \lognamedpos{lineend} \newline x\hfill \vrule height 1em \sdaps_qobject_end: \ExplSyntaxOff \end{MYTESTPAGE} \begin{MYTESTPAGE}{vhstretch: full page box} \ExplSyntaxOn % Reset counting \int_gzero:N \g__sdaps_object_id_int \sdaps_qobject_begin:nn {Text} { } \sdaps_textbox_vhstretch:nn { text } { 0cm } \break asfdasdf \sdaps_qobject_end: \ExplSyntaxOff \end{MYTESTPAGE} \begin{MYTESTPAGE}{vhstretch: box that are exactly 200pt high } \ExplSyntaxOn % Reset counting \int_gzero:N \g__sdaps_object_id_int \sdaps_qobject_begin:nn {Text} { } \setlength{\columnsep}{1pt} % Without stretching \begin{multicols}{2} \sdaps_textbox_vhstretch:nnn { text } { 200pt } { 0 } \columnbreak % This hrule is on the first baseline (\topskip from the top) \hrule height 0pt % Then go up 1.7ex (\l__sdaps_textbox_ht_dim) to get the top position \vskip -1.7ex \hrule height 1pt \vskip 198pt \hrule height 1pt \end{multicols} % And with stretching \begin{multicols}{2} \sdaps_textbox_vhstretch:nnn { text } { 0pt } { 1 } % Need an hrule here as multicols alignes the baselines \hrule height 0pt depth 0pt \columnbreak % This hrule is on the first baseline (\topskip from the top) \hrule height 0pt % Then go up 1.7ex (\l__sdaps_textbox_ht_dim) to get the top position \vskip -1.7ex \hrule height 1pt \vskip 198pt \hrule height 1pt \end{multicols} \sdaps_qobject_end: \ExplSyntaxOff \end{MYTESTPAGE} \begin{MYTESTPAGE}{vhstretch: rules at top/bottom have no distance} \ExplSyntaxOn % Reset counting \int_gzero:N \g__sdaps_object_id_int \sdaps_qobject_begin:nn {Text} { } \hrule \sdaps_textbox_vhstretch:nnn { text } { 200pt } { 0 } \lognamedpos{bottom}\hrule \sdaps_qobject_end: Visually ~ check ~ that ~ the ~ lines ~ at ~ the ~ top/bottom ~ are ~ slightly ~ thicker ~ without ~ a ~ gap. \ExplSyntaxOff \end{MYTESTPAGE} \begin{MYTESTPAGE}{vhstretch: bottom has a depth of 0.5ex} \ExplSyntaxOn % Reset counting \int_gzero:N \g__sdaps_object_id_int \sdaps_qobject_begin:nn {Text} { } % No stretch here \sdaps_textbox_vhstretch:nnn { text } { 200pt } { 0 } \dim_log:N \prevdepth \dim_compare:nNnTF { 0.5ex } = { \prevdepth } { GOOD } { BAD \ERROR } \sdaps_qobject_end: \ExplSyntaxOff \end{MYTESTPAGE} \begin{MYTESTPAGE}{vhstretch: With surrounding paragraphs} \parskip=1em \ExplSyntaxOn % Reset counting \int_gzero:N \g__sdaps_object_id_int \sdaps_qobject_begin:nn {Text} { } \sdaps_textbox_vhstretch:nnn { text } { 2cm } { 0 } \sdaps_textbox_vhstretch:nnn { text } { 2cm } { 0 } \sdaps_textbox_vhstretch:nnn { text } { 2cm } { 0 } Text~text~text~text~text~text~text~text~text~text~text~text~text~text~text~ text~text~text~text~text~text~text~text~text~text~text~text~text~text~text. \sdaps_textbox_vhstretch:nnn { text } { 2cm } { 0 } Text~text~text~text~text~text~text~text~text~text~text~text~text~text~text~ text~text~text~text~text~text~text~text~text~text~text~text~text~text~text. \sdaps_textbox_vhstretch:nnn { text } { 2cm } { 0 } \vspace{-\parskip} This~is~moved~up~by~\textbackslash parskip.~text~text~text~text~text~text~text~text~ text~text~text~text~text~text~text~text~text~text~text~text~text~text~text. \sdaps_qobject_end: \ExplSyntaxOff \end{MYTESTPAGE} \begin{MYTESTPAGE}{vhstretch: Keeping together with the previous paragraph} \parskip=1em \ExplSyntaxOn % Reset counting \int_gzero:N \g__sdaps_object_id_int \sdaps_qobject_begin:nn {Text} { } % This is just too big so that a page break must happen \sdaps_textbox_vhstretch:nnn { text } { 17.5cm } { 1 } This~text~is~at~the~top~of~the~new~page.~Text~text~text~text~text~text~text~ text~text~text~text~text~text~text~text~text~text~text~text~text~text~text. \sdaps_textbox_vhstretch:nnn { text } { 2cm } { 0 } \sdaps_qobject_end: \ExplSyntaxOff \end{MYTESTPAGE} \begin{MYTESTPAGE}{vhstretch: error in math and horizontal modes} \ExplSyntaxOn % Reset counting \int_gzero:N \g__sdaps_object_id_int \sdaps_qobject_begin:nn {Text} { } \ExplSyntaxOff \ExplSyntaxOn $\sdaps_textbox_vhstretch:nn { text } { 0cm }$ \ExplSyntaxOff \ExplSyntaxOn \hbox{\sdaps_textbox_vhstretch:nn { text } { 0cm }} \ExplSyntaxOff \ExplSyntaxOn \sdaps_qobject_end: \ExplSyntaxOff \end{MYTESTPAGE} \begin{OMITPAGE} Nothing here to see. % Enable writing out information. \ExplSyntaxOn \sdaps_end: \ExplSyntaxOff \end{OMITPAGE} \end{document} sdaps-1.9.8/tex/class/testfiles/base-textboxes.tlg0000644000175000000660000002465113600505201022753 0ustar benjaminlock00000000000000This is a generated file for the l3build validation system. Don't change this file in any respect. ============================================================ TEST 1: hstretch: visually check the outline does not overshoot ============================================================ Completed box being shipped out [2] \vbox(655.63496+0.0)x435.61176 .\hbox(0.0+0.0)x0.0 .\glue -25.16531 .\vbox(680.80028+0.0)x418.25555, shifted 17.3562 ..\vbox(17.0+0.0)x418.25555, glue set 17.0fil ...\glue 0.0 plus 1.0fil ...\hbox(0.0+0.0)x418.25555 ....\pdfcolorstack 0 push {0 g 0 G} ....\hbox(0.0+0.0)x418.25555 ....\pdfcolorstack 0 pop ..\glue 20.40001 ..\glue(\lineskip) 0.0 ..\vbox(595.80026+0.0)x418.25555, glue set 525.31975fil ...\write-{\exp_not:n {[1]QObject-Text=1. }} ...\glue(\topskip) 0.0 ...\hbox(14.22636+5.69054)x418.25555, glue set 219.08627fill ....\rule(14.22636+5.69054)x0.0 ....\penalty 10000 ....\pdfsavepos ....\write1{\noexpand \pgfsyspdfmark {textboxstart0}{\the \pdflastxpos }{\the \pdflastypos \ETC.} ....\penalty 10000 ....\glue 199.16928 plus 1.0fill ....\penalty 10000 ....\hbox(0.0+0.0)x0.0 .....\glue 0.0 .....\hbox(0.0+0.0)x0.0 ......\pdfliteral{q } ......\pdfliteral{0 G } ......\pdfliteral{0 g } ......\pdfliteral{0.3985 w } ......\hbox(0.0+0.0)x0.0 .......\pdfliteral{q } .......\glue 0.0 .......\pdfliteral{q } .......\pdfliteral{1.0 w } .......\pdfliteral{1 g } .......\pdfliteral{0 G } .......\pdfliteral{-416.19833 13.6734 m } .......\pdfliteral{-416.19833 13.6734 m } .......\pdfliteral{-416.19833 -5.16933 l } .......\pdfliteral{-0.5 -5.16933 l } .......\pdfliteral{-0.5 13.6734 l } .......\pdfliteral{h } .......\pdfliteral{-0.5 -5.16933 m } .......\pdfliteral{B } .......\glue 0.0 .......\pdfliteral{Q } .......\pdfliteral{q } .......\glue 0.0 .......\pdfliteral{Q } .......\write-{[2]Box[1]=Textbox,\int_use:N \g_sdaps_page_int ,89.62619pt,760.54225p\ETC.} .......\glue 0.0 .......\pdfliteral{Q } .......\hbox(0.0+0.0)x0.0 ........\pdfsavepos ........\write1{\noexpand \pgfsyspdfmark {pgfid1}{\the \pdflastxpos }{\the \pdflastypos \ETC.} .......\glue 0.0 plus 1.0fil minus 1.0fil ......\pdfliteral{n } ......\pdfliteral{Q } ......\glue 0.0 plus 1.0fil minus 1.0fil ....\penalty 10000 ....\glue 0.0 plus 1.0fil ....\penalty -10000 ....\glue(\rightskip) 0.0 ...\penalty 150 ...\glue(\lineskip) 1.0 ...\hbox(10.95003+0.0)x418.25555, glue set 417.45557fill ....\rule(10.95003+*)x0.4 ....\glue 0.0 plus 1.0fill ....\rule(10.95003+*)x0.4 ....\penalty 10000 ....\glue 0.0 plus 1.0fil ....\penalty -10000 ....\glue(\rightskip) 0.0 ...\glue(\lineskip) 1.0 ...\hbox(14.22636+11.38109)x418.25555, glue set 215.26122fil ....\hbox(0.0+11.38109)x0.0, glue set - 0.4fil .....\rule(*+11.38109)x0.4 .....\glue 0.0 plus 1.0fil minus 1.0fil ....\rule(14.22636+5.69054)x0.0 ....\penalty 10000 ....\pdfsavepos ....\write1{\noexpand \pgfsyspdfmark {textboxstart1}{\the \pdflastxpos }{\the \pdflastypos \ETC.} ....\penalty 10000 ....\glue 199.16928 ....\penalty 10000 ....\hbox(0.0+0.0)x0.0 .....\glue 0.0 .....\hbox(0.0+0.0)x0.0 ......\pdfliteral{q } ......\pdfliteral{0 G } ......\pdfliteral{0 g } ......\pdfliteral{0.3985 w } ......\hbox(0.0+0.0)x0.0 .......\pdfliteral{q } .......\glue 0.0 .......\pdfliteral{q } .......\pdfliteral{1.0 w } .......\pdfliteral{1 g } .......\pdfliteral{0 G } .......\pdfliteral{-197.92775 13.6734 m } .......\pdfliteral{-197.92775 13.6734 m } .......\pdfliteral{-197.92775 -5.16933 l } .......\pdfliteral{-0.5 -5.16933 l } .......\pdfliteral{-0.5 13.6734 l } .......\pdfliteral{h } .......\pdfliteral{-0.5 -5.16933 m } .......\pdfliteral{B } .......\glue 0.0 .......\pdfliteral{Q } .......\pdfliteral{q } .......\glue 0.0 .......\pdfliteral{Q } .......\write-{[3]Box[1]=Textbox,\int_use:N \g_sdaps_page_int ,89.62619pt,727.67532p\ETC.} .......\glue 0.0 .......\pdfliteral{Q } .......\hbox(0.0+0.0)x0.0 ........\pdfsavepos ........\write1{\noexpand \pgfsyspdfmark {pgfid2}{\the \pdflastxpos }{\the \pdflastypos \ETC.} .......\glue 0.0 plus 1.0fil minus 1.0fil ......\pdfliteral{n } ......\pdfliteral{Q } ......\glue 0.0 plus 1.0fil minus 1.0fil ....\hbox(0.0+11.38109)x0.0, glue set - 0.4fil .....\glue 0.0 plus 1.0fil minus 1.0fil .....\rule(*+11.38109)x0.4 ....\pdfsavepos ....\write*{POSITION at70mm: \the \pdflastxpos ,\the \pdflastypos } ....\kern 1.82506 ....\rule(14.22636+5.69054)x2.0 ....\penalty 10000 ....\glue 0.0 plus 1.0fil ....\penalty -10000 ....\glue(\rightskip) 0.0 ...\penalty 150 ...\glue(\lineskip) 1.0 ...\hbox(10.95003+0.0)x418.25555, glue set 219.08627fil ....\hbox(10.95003+0.0)x0.0, glue set - 0.4fil .....\rule(10.95003+*)x0.4 .....\glue 0.0 plus 1.0fil minus 1.0fil ....\glue 199.16928 ....\hbox(10.95003+0.0)x0.0, glue set - 0.4fil .....\glue 0.0 plus 1.0fil minus 1.0fil .....\rule(10.95003+*)x0.4 ....\write-{[4]Variable[1]=1} ....\penalty 10000 ....\glue(\parfillskip) 0.0 plus 1.0fil ....\glue(\rightskip) 0.0 ...\glue 0.0 plus 1.0fil ...\glue 0.0 ...\glue 0.0 plus 0.0001fil ..\glue(\baselineskip) 47.6 ..\hbox(0.0+0.0)x418.25555 ...\pdfcolorstack 0 push {0 g 0 G} ...\hbox(0.0+0.0)x418.25555 ...\pdfcolorstack 0 pop [1]QObject-Text=1. [2]Box[1]=Textbox,0,89.62619pt,760.54225pt,418.25555pt,19.9169pt,1.00374pt,text, [3]Box[1]=Textbox,0,89.62619pt,727.67532pt,199.16928pt,19.9169pt,1.00374pt,text, POSITION at70mm: 18926500,46756591 [4]Variable[1]=1 ============================================================ ============================================================ TEST 2: hstretch: check only specified width is used ============================================================ [3 [5]QObject-Text=1. POSITION center1: 19579140,48910558 [6]Box[1]=Textbox,0,298.75397pt,760.54225pt,209.12778pt,19.9169pt,1.00374pt,text, [7]Box[1]=Textbox,0,89.62619pt,739.62535pt,209.12778pt,19.9169pt,1.00374pt,text, POSITION center2: 19579140,47539748 [8]Variable[1]=1 ] ============================================================ ============================================================ TEST 3: hbox: check alignment ============================================================ [4 [9]QObject-Text=1. [10]Box[1]=Textbox,0,89.62619pt,757.26807pt,11.80168pt,10.73706pt,1.00374pt,text, [11]Box[1]=Textbox,0,492.18675pt,758.02847pt,15.69499pt,11.61913pt,1.00374pt,text, [12]Variable[1]=1 ] ============================================================ ============================================================ TEST 4: hbox: inside a formular ============================================================ [5 [13]QObject-Text=1. [14]Box[1]=Textbox,0,213.14265pt,748.45341pt,23.36002pt,13.62665pt,1.00374pt,text, [15]Box[1]=Textbox,0,237.70267pt,760.54225pt,270.17908pt,19.9169pt,1.00374pt,text, POSITION lineend: 33284538,48910558 [16]Variable[1]=1 ] ============================================================ ============================================================ TEST 5: vhstretch: full page box ============================================================ [6 [17]QObject-Text=1. [18]Box[1]=Textbox,0,89.62619pt,757.55699pt,418.25555pt,595.17229pt,1.00374pt,text, ] [7 [19]Variable[1]=1 ] ============================================================ ============================================================ TEST 6: vhstretch: box that are exactly 200pt high ============================================================ [8 [20]QObject-Text=1. [21]Box[1]=Textbox,0,89.62619pt,757.55699pt,208.62778pt,200.0pt,1.00374pt,text, [22]Box[1]=Textbox,0,89.62619pt,539.32901pt,208.62778pt,200.0pt,1.00374pt,text, [23]Variable[1]=1 ] ============================================================ ============================================================ TEST 7: vhstretch: rules at top/bottom have no distance ============================================================ [9 [24]QObject-Text=1. [25]Box[1]=Textbox,0,89.62619pt,749.54225pt,418.25555pt,200.0pt,1.00374pt,text, POSITION bottom: 5873742,36014801 [26]Variable[1]=1 ] ============================================================ ============================================================ TEST 8: vhstretch: bottom has a depth of 0.5ex ============================================================ > \prevdepth=2.35728pt. [10 [27]QObject-Text=1. [28]Box[1]=Textbox,0,89.62619pt,757.55699pt,418.25555pt,200.0pt,1.00374pt,text, [29]Variable[1]=1 ] ============================================================ ============================================================ TEST 9: vhstretch: With surrounding paragraphs ============================================================ [11 [30]QObject-Text=1. [31]Box[1]=Textbox,0,89.62619pt,757.55699pt,418.25555pt,56.9055pt,1.00374pt,text, [32]Box[1]=Textbox,0,89.62619pt,697.42351pt,418.25555pt,56.9055pt,1.00374pt,text, [33]Box[1]=Textbox,0,89.62619pt,637.29002pt,418.25555pt,56.9055pt,1.00374pt,text, [34]Box[1]=Textbox,0,89.62619pt,539.0065pt,418.25555pt,56.9055pt,1.00374pt,text, [35]Box[1]=Textbox,0,89.62619pt,440.72298pt,418.25555pt,56.9055pt,1.00374pt,text, [36]Variable[1]=1 ] ============================================================ ============================================================ TEST 10: vhstretch: Keeping together with the previous paragraph ============================================================ [12 [37]QObject-Text=1. [38]Box[1]=Textbox,0,89.62619pt,757.55699pt,418.25555pt,595.17229pt,1.00374pt,text, ] [13 [39]Box[1]=Textbox,0,89.62619pt,730.35698pt,418.25555pt,56.9055pt,1.00374pt,text, [40]Variable[1]=1 ] ============================================================ ============================================================ TEST 11: vhstretch: error in math and horizontal modes ============================================================ ! Package sdapsbase Error: Impossible to layout a vhstretch textbox in math (sdapsbase) mode. Type to continue. ... l. ......aps_textbox_vhstretch:nn { text } { 0cm } $ LaTeX does not know anything more about this error, sorry. Try typing to proceed. If that doesn't work, type X to quit. ! Package sdapsbase Error: Impossible to layout a vhstretch textbox in (sdapsbase) horizontal mode. Type to continue. ... l. ......aps_textbox_vhstretch:nn { text } { 0cm } } LaTeX does not know anything more about this error, sorry. Try typing to proceed. If that doesn't work, type X to quit. [14 [41]QObject-Text=1. [42]Variable[1]=1 ] ============================================================ (base-textboxes.aux) sdaps-1.9.8/tex/class/testfiles/base-textboxes.xetex.tlg0000644000175000000660000002551513600505201024107 0ustar benjaminlock00000000000000This is a generated file for the l3build validation system. Don't change this file in any respect. ============================================================ TEST 1: hstretch: visually check the outline does not overshoot ============================================================ Completed box being shipped out [2] \vbox(655.63496+0.0)x435.61176 .\hbox(0.0+0.0)x0.0 ..\special{pdf:put @resources << /ColorSpace @pgfcolorspaces >>} .\glue -25.16531 .\vbox(680.80028+0.0)x418.25555, shifted 17.3562 ..\vbox(17.0+0.0)x418.25555, glue set 17.0fil ...\glue 0.0 plus 1.0fil ...\hbox(0.0+0.0)x418.25555 ....\special{color push gray 0} ....\hbox(0.0+0.0)x418.25555 ....\special{color pop} ..\glue 20.40001 ..\glue(\lineskip) 0.0 ..\vbox(595.80026+0.0)x418.25555, glue set 525.31981fil ...\write-{\exp_not:n {[1]QObject-Text=1. }} ...\glue(\topskip) 0.0 ...\hbox(14.22636+5.69054)x418.25555, glue set 219.08627fill ....\rule(14.22636+5.69054)x0.0 ....\penalty 10000 ....\pdfsavepos ....\write1{\noexpand \pgfsyspdfmark {textboxstart0}{\the \pdflastxpos }{\the \pdflastypos \ETC.} ....\penalty 10000 ....\glue 199.16928 plus 1.0fill ....\penalty 10000 ....\hbox(0.0+0.0)x0.0 .....\glue 0.0 .....\hbox(0.0+0.0)x0.0 ......\special{pdf:bcontent} ......\special{pdf:code q } ......\special{pdf:code 0 G } ......\special{pdf:code 0 g } ......\special{pdf:code 0.3985 w } ......\hbox(0.0+0.0)x0.0 .......\special{pdf:code q } .......\glue 0.0 .......\special{pdf:code q } .......\special{pdf:code 1.0 w } .......\special{pdf:code 1 g } .......\special{pdf:code 0 G } .......\special{pdf:code -416.19833 13.6734 m } .......\special{pdf:code -416.19833 13.6734 m } .......\special{pdf:code -416.19833 -5.16933 l } .......\special{pdf:code -0.5 -5.16933 l } .......\special{pdf:code -0.5 13.6734 l } .......\special{pdf:code h } .......\special{pdf:code -0.5 -5.16933 m } .......\special{pdf:code B } .......\glue 0.0 .......\special{pdf:code Q } .......\special{pdf:code q } .......\glue 0.0 .......\special{pdf:code Q } .......\write-{[2]Box[1]=Textbox,\int_use:N \g_sdaps_page_int ,89.62619pt,760.54225p\ETC.} .......\glue 0.0 .......\special{pdf:code Q } .......\hbox(0.0+0.0)x0.0 ........\pdfsavepos ........\write1{\noexpand \pgfsyspdfmark {pgfid1}{\the \pdflastxpos }{\the \pdflastypos \ETC.} .......\glue 0.0 plus 1.0fil minus 1.0fil ......\special{pdf:code n } ......\special{pdf:code Q } ......\special{pdf:econtent} ......\glue 0.0 plus 1.0fil minus 1.0fil ....\penalty 10000 ....\glue 0.0 plus 1.0fil ....\penalty -10000 ....\glue(\rightskip) 0.0 ...\penalty 150 ...\glue(\lineskip) 1.0 ...\hbox(10.95+0.0)x418.25555, glue set 417.45557fill ....\rule(10.95+*)x0.4 ....\glue 0.0 plus 1.0fill ....\rule(10.95+*)x0.4 ....\penalty 10000 ....\glue 0.0 plus 1.0fil ....\penalty -10000 ....\glue(\rightskip) 0.0 ...\glue(\lineskip) 1.0 ...\hbox(14.22636+11.38109)x418.25555, glue set 215.26123fil ....\hbox(0.0+11.38109)x0.0, glue set - 0.4fil .....\rule(*+11.38109)x0.4 .....\glue 0.0 plus 1.0fil minus 1.0fil ....\rule(14.22636+5.69054)x0.0 ....\penalty 10000 ....\pdfsavepos ....\write1{\noexpand \pgfsyspdfmark {textboxstart1}{\the \pdflastxpos }{\the \pdflastypos \ETC.} ....\penalty 10000 ....\glue 199.16928 ....\penalty 10000 ....\hbox(0.0+0.0)x0.0 .....\glue 0.0 .....\hbox(0.0+0.0)x0.0 ......\special{pdf:bcontent} ......\special{pdf:code q } ......\special{pdf:code 0 G } ......\special{pdf:code 0 g } ......\special{pdf:code 0.3985 w } ......\hbox(0.0+0.0)x0.0 .......\special{pdf:code q } .......\glue 0.0 .......\special{pdf:code q } .......\special{pdf:code 1.0 w } .......\special{pdf:code 1 g } .......\special{pdf:code 0 G } .......\special{pdf:code -197.92775 13.6734 m } .......\special{pdf:code -197.92775 13.6734 m } .......\special{pdf:code -197.92775 -5.16933 l } .......\special{pdf:code -0.5 -5.16933 l } .......\special{pdf:code -0.5 13.6734 l } .......\special{pdf:code h } .......\special{pdf:code -0.5 -5.16933 m } .......\special{pdf:code B } .......\glue 0.0 .......\special{pdf:code Q } .......\special{pdf:code q } .......\glue 0.0 .......\special{pdf:code Q } .......\write-{[3]Box[1]=Textbox,\int_use:N \g_sdaps_page_int ,89.62619pt,727.67535p\ETC.} .......\glue 0.0 .......\special{pdf:code Q } .......\hbox(0.0+0.0)x0.0 ........\pdfsavepos ........\write1{\noexpand \pgfsyspdfmark {pgfid2}{\the \pdflastxpos }{\the \pdflastypos \ETC.} .......\glue 0.0 plus 1.0fil minus 1.0fil ......\special{pdf:code n } ......\special{pdf:code Q } ......\special{pdf:econtent} ......\glue 0.0 plus 1.0fil minus 1.0fil ....\hbox(0.0+11.38109)x0.0, glue set - 0.4fil .....\glue 0.0 plus 1.0fil minus 1.0fil .....\rule(*+11.38109)x0.4 ....\pdfsavepos ....\write*{POSITION at70mm: \the \pdflastxpos ,\the \pdflastypos } ....\kern 1.82504 ....\rule(14.22636+5.69054)x2.0 ....\penalty 10000 ....\glue 0.0 plus 1.0fil ....\penalty -10000 ....\glue(\rightskip) 0.0 ...\penalty 150 ...\glue(\lineskip) 1.0 ...\hbox(10.95+0.0)x418.25555, glue set 219.08627fil ....\hbox(10.95+0.0)x0.0, glue set - 0.4fil .....\rule(10.95+*)x0.4 .....\glue 0.0 plus 1.0fil minus 1.0fil ....\glue 199.16928 ....\hbox(10.95+0.0)x0.0, glue set - 0.4fil .....\glue 0.0 plus 1.0fil minus 1.0fil .....\rule(10.95+*)x0.4 ....\write-{[4]Variable[1]=1} ....\penalty 10000 ....\glue(\parfillskip) 0.0 plus 1.0fil ....\glue(\rightskip) 0.0 ...\glue 0.0 plus 1.0fil ...\glue 0.0 ...\glue 0.0 plus 0.0001fil ..\glue(\baselineskip) 47.6 ..\hbox(0.0+0.0)x418.25555 ...\special{color push gray 0} ...\hbox(0.0+0.0)x418.25555 ...\special{color pop} [1]QObject-Text=1. [2]Box[1]=Textbox,0,89.62619pt,760.54225pt,418.25555pt,19.9169pt,1.00374pt,text, [3]Box[1]=Textbox,0,89.62619pt,727.67535pt,199.16928pt,19.9169pt,1.00374pt,text, POSITION at70mm: 18926500,46756593 [4]Variable[1]=1 ============================================================ ============================================================ TEST 2: hstretch: check only specified width is used ============================================================ [3 [5]QObject-Text=1. POSITION center1: 19579140,48910558 [6]Box[1]=Textbox,0,298.75397pt,760.54225pt,209.12778pt,19.9169pt,1.00374pt,text, [7]Box[1]=Textbox,0,89.62619pt,739.62535pt,209.12778pt,19.9169pt,1.00374pt,text, POSITION center2: 19579140,47539748 [8]Variable[1]=1 ] ============================================================ ============================================================ TEST 3: hbox: check alignment ============================================================ [4 [9]QObject-Text=1. [10]Box[1]=Textbox,0,89.62619pt,757.27295pt,11.8041pt,10.74194pt,1.00374pt,text, [11]Box[1]=Textbox,0,492.18677pt,758.02484pt,15.69498pt,11.74202pt,1.00374pt,text, [12]Variable[1]=1 ] ============================================================ ============================================================ TEST 4: hbox: inside a formular ============================================================ [5 [13]QObject-Text=1. [14]Box[1]=Textbox,0,213.1426pt,748.45341pt,23.3673pt,13.74223pt,1.00374pt,text, [15]Box[1]=Textbox,0,237.70988pt,760.54225pt,270.17186pt,19.9169pt,1.00374pt,text, POSITION lineend: 33284538,48910558 [16]Variable[1]=1 ] ============================================================ ============================================================ TEST 5: vhstretch: full page box ============================================================ [6 [17]QObject-Text=1. [18]Box[1]=Textbox,0,89.62619pt,757.56529pt,418.25555pt,595.18303pt,1.00374pt,text, ] [7 [19]Variable[1]=1 ] ============================================================ ============================================================ TEST 6: vhstretch: box that are exactly 200pt high ============================================================ [8 [20]QObject-Text=1. [21]Box[1]=Textbox,0,89.62619pt,757.56529pt,208.62778pt,200.0pt,1.00374pt,text, [22]Box[1]=Textbox,0,89.62619pt,539.34805pt,208.62778pt,200.0pt,1.00374pt,text, [23]Variable[1]=1 ] ============================================================ ============================================================ TEST 7: vhstretch: rules at top/bottom have no distance ============================================================ [9 [24]QObject-Text=1. [25]Box[1]=Textbox,0,89.62619pt,749.54225pt,418.25555pt,200.0pt,1.00374pt,text, POSITION bottom: 5873742,36014801 [26]Variable[1]=1 ] ============================================================ ============================================================ TEST 8: vhstretch: bottom has a depth of 0.5ex ============================================================ > \prevdepth=2.35973pt. [10 [27]QObject-Text=1. [28]Box[1]=Textbox,0,89.62619pt,757.56529pt,418.25555pt,200.0pt,1.00374pt,text, [29]Variable[1]=1 ] ============================================================ ============================================================ TEST 9: vhstretch: With surrounding paragraphs ============================================================ [11 [30]QObject-Text=1. [31]Box[1]=Textbox,0,89.62619pt,757.56529pt,418.25555pt,56.9055pt,1.00374pt,text, [32]Box[1]=Textbox,0,89.62619pt,697.44255pt,418.25555pt,56.9055pt,1.00374pt,text, [33]Box[1]=Textbox,0,89.62619pt,637.31981pt,418.25555pt,56.9055pt,1.00374pt,text, [34]Box[1]=Textbox,0,89.62619pt,539.04706pt,418.25555pt,56.9055pt,1.00374pt,text, [35]Box[1]=Textbox,0,89.62619pt,440.7743pt,418.25555pt,56.9055pt,1.00374pt,text, [36]Variable[1]=1 ] ============================================================ ============================================================ TEST 10: vhstretch: Keeping together with the previous paragraph ============================================================ [12 [37]QObject-Text=1. [38]Box[1]=Textbox,0,89.62619pt,757.56529pt,418.25555pt,595.18303pt,1.00374pt,text, ] [13 [39]Box[1]=Textbox,0,89.62619pt,730.36528pt,418.25555pt,56.9055pt,1.00374pt,text, [40]Variable[1]=1 ] ============================================================ ============================================================ TEST 11: vhstretch: error in math and horizontal modes ============================================================ ! Package sdapsbase Error: Impossible to layout a vhstretch textbox in math (sdapsbase) mode. Type to continue. ... l. ......aps_textbox_vhstretch:nn { text } { 0cm } $ LaTeX does not know anything more about this error, sorry. Try typing to proceed. If that doesn't work, type X to quit. ! Package sdapsbase Error: Impossible to layout a vhstretch textbox in (sdapsbase) horizontal mode. Type to continue. ... l. ......aps_textbox_vhstretch:nn { text } { 0cm } } LaTeX does not know anything more about this error, sorry. Try typing to proceed. If that doesn't work, type X to quit. [14 [41]QObject-Text=1. [42]Variable[1]=1 ] ============================================================ (base-textboxes.aux) sdaps-1.9.8/tex/class/testfiles/base.lvt0000644000175000000660000003347613255764711020777 0ustar benjaminlock00000000000000\documentclass{scrartcl} \input{regression-test} \OMIT \usepackage{sdapsbase} % To properly call \sdaps_page_end: for each page. \usepackage{scrpage2} \def\logpos#1{\lognamedpos{#1}#1} \def\lognamedpos#1{\pdfsavepos\write128{POSITION #1: \the\pdflastxpos,\the\pdflastypos}} \newenvironment{MYTEST}[1]{% \begingroup% \global\advance \gTESTint 1 % \SEPARATOR% \LONGTYPEOUT{% TEST \the\gTESTint: \detokenize{#1}}% \SEPARATOR% }{% \SEPARATOR% \LONGTYPEOUT{}% \endgroup% } \newenvironment{OMITPAGE}{% \begingroup% \OMIT% }{% \vfil\break% \TIMO% \endgroup% } \newenvironment{MYTESTPAGE}[1]{% \begin{MYTEST}{#1}% }{% \vfil\break% \end{MYTEST}% } \newenvironment{MYTESTPAGESHOW}[1]{% \begin{MYTESTPAGE}{#1}% \showoutput% }{% \end{MYTESTPAGE}% } \TIMO \begin{document} \START \ExplSyntaxOn % This needs to be before the document starts \pagestyle{scrheadings} \clearscrheadings \cfoot{\sdaps_page_end:} \ExplSyntaxOff \OMIT % Some font stuff $ a + b $ % Enable writing out information. \ExplSyntaxOn % Redirect output to log file instead of .sdaps file \iow_close:N \g_sdaps_infofile_iow \global\let\g_sdaps_infofile_iow=\c_log_iow \ExplSyntaxOff \textbackslash \TIMO % NOTE: This test has to be in global scope as of now! \SEPARATOR \TYPE{Setting overrides throws no errors} \SEPARATOR % This needs to test specific/unspecific QID and then matching all elements, by % variable name and by variable name and value. % We don't test values here, these tests are elsewhere and it is safe to modify % the overrides here to add items for other tests \ExplSyntaxOn \sdaps_overrides_init:n{ *={ *={}, var1={}, var2&val1={}, }, qid1={ *={}, var1={}, var2&val1={}, }, testoverrideqid={ *={height=5mm}, testvar={height=10mm}, 3_testvar={height=12.5mm}, testvar&testval={height=15mm}, prefix_1={height=7mm}, prefix_testvar={height=10mm}, prefix_testvar&testval={height=15mm}, }, } \ExplSyntaxOff \SEPARATOR \begin{MYTESTPAGE}{Initialize SDAPS} \ExplSyntaxOn \sdaps_context_enable_writing: \sdaps_begin: \sdaps_context_disable_writing: \ExplSyntaxOff Start of the document \end{MYTESTPAGE} \begin{MYTEST}{Test nested unwrapping of context scopes} \ExplSyntaxOn { \sdaps_context_begin_local: \sdaps_context_begin: \sdaps_context_set:n {test=value} \sdaps_context_begin:n { testcontext } \sdaps_context_get:nN { test } \l_tmpa_tl \tl_if_eq:VnTF \l_tmpa_tl { value } {} { \ERROR } } \sdaps_context_get:nN { test } \l_tmpa_tl \tl_if_eq:VnTF \l_tmpa_tl { value } { \ERROR } { } { \sdaps_context_begin_local: \sdaps_context_set:n {test=value1} \sdaps_context_begin:n { testcontext1 } \sdaps_context_set:n {test=value2} \sdaps_context_begin:n { testcontext2 } % value2 \sdaps_context_get:nN { test } \l_tmpa_tl \tl_if_eq:VnTF \l_tmpa_tl { value2 } { } { \ERROR } \sdaps_context_end:n { testcontext1 } % value1 \sdaps_context_get:nN { test } \l_tmpa_tl \tl_if_eq:VnTF \l_tmpa_tl { value1 } { } { \ERROR } } % And cleared again \sdaps_context_get:nN { test } \l_tmpa_tl \tl_if_eq:VnTF \l_tmpa_tl { value } { \ERROR } {} \ExplSyntaxOff \end{MYTEST} \begin{MYTESTPAGE}{Check metadata error handling} \ExplSyntaxOn % First output a checkbox without metadata writing \noindent\sdaps_checkbox:nn {} {} \newline % Enable metadata writing (active for all other tests from now on) % But without setting a QID \sdaps_context_enable_writing: \sdaps_checkbox:nn {} {} \newline % Now start a choicequestion { \sdaps_qobject_begin_local:nn {Choice} { A~choice~question } \sdaps_checkbox:nn {} {} } \ExplSyntaxOff \end{MYTESTPAGE} \begin{MYTESTPAGE}{Check whether overrides and variable generation are working} \ExplSyntaxOn \noindent \sdaps_set_questionnaire_id:n{testoverrideqid} { \sdaps_qobject_begin_local:nn {Choice} { A~choice~question } \sdaps_checkbox:nn {} {} {}~ \sdaps_checkbox:nn { testvar } {} {}~ \sdaps_checkbox:nn { _testvar } {} {}~ \sdaps_checkbox:nn { testvar } { testval } {} } \newline { \sdaps_qobject_begin_local:nn {Choice} { A~choice~question } \sdaps_qobject_append_var:n { prefix } \sdaps_checkbox:nn {} {} {}~ \sdaps_checkbox:nn { testvar } {} {}~ \sdaps_checkbox:nn { _testvar } {} {}~ \sdaps_checkbox:nn { testvar } { testval } {} } % Reset QID back to normal \sdaps_set_questionnaire_id:n{testqid} \ExplSyntaxOff \end{MYTESTPAGE} \begin{MYTESTPAGE}{Check whether context appending is working} \ExplSyntaxOn { \sdaps_qobject_begin_local:nn {Choice} { A~choice~question } \sdaps_context_append:nn { * } { height=5mm } \sdaps_checkbox:nn {} {} {}~ \sdaps_context_append:nn { multichoice } { height=10mm } \sdaps_checkbox:nn {} {} } \ExplSyntaxOff \end{MYTESTPAGE} \begin{MYTESTPAGE}{Check different checkbox designs and font sizes} \ExplSyntaxOn { \sdaps_qobject_begin_local:nn {Choice} { A~choice~question } \noindent\tiny Text~with~underhang~ \sdaps_checkbox:nn {} {} {}~Text~with~underhang \newline \scriptsize Text~with~underhang~ \sdaps_checkbox:nn {} {} {}~Text~with~underhang \newline \footnotesize Text~with~underhang~ \sdaps_checkbox:nn {} {} {}~Text~with~underhang \newline \small Text~with~underhang~ \sdaps_checkbox:nn {} {} {}~Text~with~underhang \newline \normalsize Text~with~underhang~ \sdaps_checkbox:nn {} {} {}~Text~with~underhang \newline \large Text~with~underhang~ \sdaps_checkbox:nn {} {} {}~Text~with~underhang \newline \Large Text~with~underhang~ \sdaps_checkbox:nn {} {} {}~Text~with~underhang \newline \huge Text~with~underhang~ \sdaps_checkbox:nn {} {} {}~Text~with~underhang \newline \Huge Text~with~underhang~ \sdaps_checkbox:nn {} {} {}~Text \par \sdaps_context_append:nn { multichoice } { ellipse } \noindent\tiny Text~with~underhang~ \sdaps_checkbox:nn {} {} {}~Text~with~underhang \newline \scriptsize Text~with~underhang~ \sdaps_checkbox:nn {} {} {}~Text~with~underhang \newline \footnotesize Text~with~underhang~ \sdaps_checkbox:nn {} {} {}~Text~with~underhang \newline \small Text~with~underhang~ \sdaps_checkbox:nn {} {} {}~Text~with~underhang \newline \normalsize Text~with~underhang~ \sdaps_checkbox:nn {} {} {}~Text~with~underhang \newline \large Text~with~underhang~ \sdaps_checkbox:nn {} {} {}~Text~with~underhang \newline \Large Text~with~underhang~ \sdaps_checkbox:nn {} {} {}~Text~with~underhang \newline \huge Text~with~underhang~ \sdaps_checkbox:nn {} {} {}~Text~with~underhang \newline \Huge Text~with~underhang~ \sdaps_checkbox:nn {} {} {}~Text \par } \ExplSyntaxOff \end{MYTESTPAGE} \begin{MYTESTPAGE}{Checkbox line width, form and fill setting} \ExplSyntaxOn { \sdaps_qobject_begin_local:nn {Choice} { A~choice~question } \noindent \sdaps_context_set:n { multichoice={ box,fill=red } } \sdaps_checkbox:nn {} {} \sdaps_context_set:n { multichoice={ box,linewidth=2bp,fill=red } } \sdaps_checkbox:nn {} {}\newline \sdaps_context_set:n { multichoice={ ellipse,fill=red } } \sdaps_checkbox:nn {} {} \sdaps_context_set:n { multichoice={ ellipse,linewidth=2bp,fill=red } } \sdaps_checkbox:nn {} {}\newline \sdaps_context_set:n { multichoice={ form=box,fill=red } } \sdaps_checkbox:nn {} {} \sdaps_context_set:n { multichoice={ form=box,linewidth=2bp,fill=red } } \sdaps_checkbox:nn {} {}\newline \sdaps_context_set:n { multichoice={ form=ellipse,fill=red } } \sdaps_checkbox:nn {} {} \sdaps_context_set:n { multichoice={ form=ellipse,linewidth=2bp,fill=red } } \sdaps_checkbox:nn {} {}\newline The~above~checkboxes~should~be~filled~red.~The~right~column~has~thicker~ line~widths.~Box/Ellipse~style~iterate. } \ExplSyntaxOff \end{MYTESTPAGE} \begin{MYTESTPAGE}{multichoice/singlechoice switching} \ExplSyntaxOn { \sdaps_qobject_begin_local:nn {Choice} { A~choice~question } \noindent \sdaps_checkbox_set_type:n { multichoice } \sdaps_context_set:n { multichoice={ fill=red }, singlechoice={} } \sdaps_checkbox:nn {} {} \sdaps_context_set:n { multichoice={ linewidth=2bp,fill=red }, singlechoice={} } \sdaps_checkbox:nn {} {}\newline \sdaps_checkbox_set_type:n { singlechoice } \sdaps_context_set:n { singlechoice={ fill=red }, multichoice={} } \sdaps_checkbox:nn {} {} \sdaps_context_set:n { singlechoice={ linewidth=2bp,fill=red }, multichoice={} } \sdaps_checkbox:nn {} {}\newline \sdaps_checkbox_set_type:n { multichoice } \sdaps_context_set:n { multichoice={ form=box,fill=red }, singlechoice={} } \sdaps_checkbox:nn {} {} \sdaps_context_set:n { mulitchoice={ form=box,linewidth=2bp,fill=red }, singlechoice={} } \sdaps_checkbox:nn {} {}\newline \sdaps_checkbox_set_type:n { singlechoice } \sdaps_context_set:n { singlechoice={ fill=red }, multichoice={} } \sdaps_checkbox:nn {} {} \sdaps_context_set:n { singlechoice={ linewidth=2bp,fill=red }, multichoice={} } \sdaps_checkbox:nn {} {}\newline The~above~checkboxes~should~be~filled~red.~The~right~column~has~thicker~ line~widths.~Box/Ellipse~style~iterate. } \ExplSyntaxOff \end{MYTESTPAGE} \begin{MYTESTPAGE}{Checkbox overlays} \ExplSyntaxOn { \sdaps_qobject_begin_local:nn {Choice} { A~choice~question } \noindent \sdaps_context_set:n { multichoice={ centered_text={\logpos{X}} } } \sdaps_checkbox:nn {} {}\newline \sdaps_context_set:n { multichoice={ draw_check } } \sdaps_checkbox:nn {} {} {} ~ \sdaps_context_set:n { multichoice={ draw_check,width=5mm,height=5mm } } \sdaps_checkbox:nn {} {} {} ~ \sdaps_context_set:n { multichoice={ draw_check,width=10mm,height=5mm } } \sdaps_checkbox:nn {} {} {} ~ \sdaps_context_set:n { multichoice={ draw_check,width=5mm,height=10mm } } \sdaps_checkbox:nn {} {}\newline \sdaps_context_set:n { multichoice={ draw_check,ellipse } } \sdaps_checkbox:nn {} {} {} ~ \sdaps_context_set:n { multichoice={ draw_check,ellipse,width=5mm,height=5mm } } \sdaps_checkbox:nn {} {} {} ~ \sdaps_context_set:n { multichoice={ draw_check,ellipse,width=10mm,height=5mm } } \sdaps_checkbox:nn {} {} {} ~ \sdaps_context_set:n { multichoice={ draw_check,ellipse,width=5mm,height=10mm } } \sdaps_checkbox:nn {} {}\newline \sdaps_context_set:n { multichoice={ text={\raggedright\logpos{Minipage}~more~text},width=5em,height=4em } } \sdaps_checkbox:nn {} {} {} ~ \sdaps_context_set:n { multichoice={ text={\raggedleft\logpos{Minipage}~more~text},width=5em,height=4em } } \sdaps_checkbox:nn {} {}\newline \sdaps_context_set:n { multichoice={ text={\raggedright\logpos{Minipage}~more~text},text_align={t},width=5em,height=4em } } \sdaps_checkbox:nn {} {} {} ~ \sdaps_context_set:n { multichoice={ text={\raggedleft\logpos{Minipage}~more~text},text_align={t},width=5em,height=4em } } \sdaps_checkbox:nn {} {}\newline \sdaps_context_set:n { multichoice={ text={\raggedright\logpos{Minipage}~more~text},text_align={b},width=5em,height=4em } } \sdaps_checkbox:nn {} {} {} ~ \sdaps_context_set:n { multichoice={ text={\raggedleft\logpos{Minipage}~more~text},text_align={b},width=5em,height=4em } } \sdaps_checkbox:nn {} {}\newline \sdaps_context_set:n { multichoice={ text={\raggedright\logpos{Minipage}~more~text},width=5em,height=4em,text_padding=0pt } } \sdaps_checkbox:nn {} {} {} ~ \sdaps_context_set:n { multichoice={ text={\raggedleft\logpos{Minipage}~more~text},width=5em,height=4em,text_padding=0pt } } \sdaps_checkbox:nn {} {}\newline \sdaps_context_set:n { multichoice={ text={\raggedright\logpos{Minipage}~more~text},text_align={t},width=5em,height=4em,text_padding=0pt } } \sdaps_checkbox:nn {} {} {} ~ \sdaps_context_set:n { multichoice={ text={\raggedleft\logpos{Minipage}~more~text},text_align={t},width=5em,height=4em,text_padding=0pt } } \sdaps_checkbox:nn {} {}\newline \sdaps_context_set:n { multichoice={ text={\raggedright\logpos{Minipage}~more~text},text_align={b},width=5em,height=4em,text_padding=0pt } } \sdaps_checkbox:nn {} {} {} ~ \sdaps_context_set:n { multichoice={ text={\raggedleft\logpos{Minipage}~more~text},text_align={b},width=5em,height=4em,text_padding=0pt } } \sdaps_checkbox:nn {} {}\newline } \ExplSyntaxOff \end{MYTESTPAGE} \begin{MYTEST}{Finish the SDAPS document, only modifies global state} \ExplSyntaxOn \sdaps_end: \bool_if:NF \g__sdaps_last_page_bool { \ERROR } \ExplSyntaxOff \end{MYTEST} \begin{MYTESTPAGE}{Flush out the last page (writes the page number)} % Finish the last page \end{MYTESTPAGE} \end{document} sdaps-1.9.8/tex/class/testfiles/base.tlg0000644000175000000660000002777313600505201020740 0ustar benjaminlock00000000000000This is a generated file for the l3build validation system. Don't change this file in any respect. ============================================================ Setting overrides throws no errors ============================================================ ============================================================ ============================================================ TEST 1: Initialize SDAPS ============================================================ ** Code 128 ** input: 324989230001 encoded: \startC ,32,49,89,23,00,01,85,\stop , black-white: 21123223212121133121214131213121222222212212421123311120 [1 [1]Duplex=false [2]PrintQuestionnaireId=0 [3]PageSize=597.50793pt,845.04694pt [4]Style=code128 [5]CheckMode=checkcorrect [6]GlobalID= [7]GlobalIDLabel= ] ============================================================ ============================================================ TEST 2: Test nested unwrapping of context scopes ============================================================ ============================================================ ============================================================ TEST 3: Check metadata error handling ============================================================ Package sdapsbase Warning: Trying to output metadata but no question ID is set (sdapsbase) on the context. Did you start a question? (sdapsbase) Supressing the output! ** Code 128 ** input: 324989230002 encoded: \startC ,32,49,89,23,00,02,91,\stop , black-white: 21123223212121133121214131213121222222222141212123311120 [2 [8]QObject-Choice=2. A choice question [9]Box[2]=Checkbox,2,89.62619pt,731.09314pt,9.95845pt,9.95845pt,box,1.00374pt,2_1,1 [10]Variable[2]=2 [11]Pages=2 ] ============================================================ ============================================================ TEST 4: Check whether overrides and variable generation are working ============================================================ ** Code 128 ** input: testqid encoded: \startB ,84,69,83,84,81,73,68,67,\stop , black-white: 21121412411211221411421212411212114214211214122114112223311120 ** Code 128 ** input: 324989230003 encoded: \startC ,32,49,89,23,00,03,97,\stop , black-white: 21123223212121133121214131213121222212122341111323311120 [3 [12]QObject-Choice=3. A choice question [13]Box[3]=Checkbox,3,89.62619pt,746.31589pt,9.95845pt,14.22636pt,box,1.00374pt,3_1,1 [14]Box[3]=Checkbox,3,103.23462pt,753.42908pt,9.95845pt,28.45274pt,box,1.00374pt,testvar,2 [15]Box[3]=Checkbox,3,116.84305pt,756.98567pt,9.95845pt,35.56593pt,box,1.00374pt,3_testvar,3 [16]Box[3]=Checkbox,3,130.45148pt,760.54227pt,9.95845pt,42.67912pt,box,1.00374pt,testvar,testval [17]Variable[3]=3 [18]QObject-Choice=4. A choice question [19]Box[4]=Checkbox,3,89.62619pt,705.48206pt,9.95845pt,19.91692pt,box,1.00374pt,prefix_1,1 [20]Box[4]=Checkbox,3,103.23462pt,709.74997pt,9.95845pt,28.45274pt,box,1.00374pt,prefix_testvar,2 [21]Box[4]=Checkbox,3,116.84305pt,709.74997pt,9.95845pt,28.45274pt,box,1.00374pt,prefix_testvar,3 [22]Box[4]=Checkbox,3,130.45148pt,716.86316pt,9.95845pt,42.67912pt,box,1.00374pt,prefix_testvar,testval [23]Variable[4]=prefix [24]Pages=3 ] ============================================================ ============================================================ TEST 5: Check whether context appending is working ============================================================ ** Code 128 ** input: testqid encoded: \startB ,84,69,83,84,81,73,68,67,\stop , black-white: 21121412411211221411421212411212114214211214122114112223311120 ** Code 128 ** input: 324989230004 encoded: \startC ,32,49,89,23,00,04,0,\stop , black-white: 21123223212121133121214131213121222212132221222223311120 [4 [25]QObject-Choice=5. A choice question [26]Box[5]=Checkbox,4,100.57622pt,753.42908pt,9.95845pt,14.22636pt,box,1.00374pt,5_1,1 [27]Box[5]=Checkbox,4,114.18465pt,760.54227pt,9.95845pt,28.45274pt,box,1.00374pt,5_2,2 [28]Variable[5]=5 [29]Pages=4 ] ============================================================ ============================================================ TEST 6: Check different checkbox designs and font sizes ============================================================ ** Code 128 ** input: testqid encoded: \startB ,84,69,83,84,81,73,68,67,\stop , black-white: 21121412411211221411421212411212114214211214122114112223311120 ** Code 128 ** input: 324989230005 encoded: \startC ,32,49,89,23,00,05,6,\stop , black-white: 21123223212121133121214131213121222213122212221323311120 [5 [30]QObject-Choice=6. A choice question [31]Box[6]=Checkbox,5,159.84755pt,756.58813pt,9.95845pt,9.95845pt,box,1.00374pt,6_1,1 [32]Box[6]=Checkbox,5,170.85652pt,727.27704pt,9.95845pt,9.95845pt,box,1.00374pt,6_2,2 [33]Box[6]=Checkbox,5,178.04225pt,697.62148pt,9.95845pt,9.95845pt,box,1.00374pt,6_3,3 [34]Box[6]=Checkbox,5,185.2097pt,667.96593pt,9.95845pt,9.95845pt,box,1.00374pt,6_4,4 [35]Box[6]=Checkbox,5,194.29005pt,638.29315pt,9.95845pt,9.95845pt,box,1.00374pt,6_5,5 [36]Box[6]=Checkbox,5,201.9028pt,608.65483pt,9.95845pt,9.95845pt,box,1.00374pt,6_6,6 [37]Box[6]=Checkbox,5,224.35782pt,579.48149pt,9.95845pt,9.95845pt,box,1.00374pt,6_7,7 [38]Box[6]=Checkbox,5,271.19269pt,551.66422pt,9.95845pt,9.95845pt,box,1.00374pt,6_8,8 [39]Box[6]=Checkbox,5,307.436pt,523.09pt,9.95845pt,9.95845pt,box,1.00374pt,6_9,9 [40]Box[6]=Checkbox,5,159.84755pt,486.58813pt,9.95845pt,9.95845pt,ellipse,1.00374pt,6_10,10 [41]Box[6]=Checkbox,5,170.85652pt,457.27704pt,9.95845pt,9.95845pt,ellipse,1.00374pt,6_11,11 [42]Box[6]=Checkbox,5,178.04225pt,427.62148pt,9.95845pt,9.95845pt,ellipse,1.00374pt,6_12,12 [43]Box[6]=Checkbox,5,185.2097pt,397.96593pt,9.95845pt,9.95845pt,ellipse,1.00374pt,6_13,13 [44]Box[6]=Checkbox,5,194.29005pt,368.29315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,6_14,14 [45]Box[6]=Checkbox,5,201.9028pt,338.65483pt,9.95845pt,9.95845pt,ellipse,1.00374pt,6_15,15 [46]Box[6]=Checkbox,5,224.35782pt,309.48149pt,9.95845pt,9.95845pt,ellipse,1.00374pt,6_16,16 [47]Box[6]=Checkbox,5,271.19269pt,281.66422pt,9.95845pt,9.95845pt,ellipse,1.00374pt,6_17,17 [48]Box[6]=Checkbox,5,307.436pt,253.09pt,9.95845pt,9.95845pt,ellipse,1.00374pt,6_18,18 [49]Variable[6]=6 [50]Pages=5 ] ============================================================ ============================================================ TEST 7: Checkbox line width, form and fill setting ============================================================ ** Code 128 ** input: testqid encoded: \startB ,84,69,83,84,81,73,68,67,\stop , black-white: 21121412411211221411421212411212114214211214122114112223311120 ** Code 128 ** input: 324989230006 encoded: \startC ,32,49,89,23,00,06,12,\stop , black-white: 21123223212121133121214131213121222212221311223223311120 [6 [51]QObject-Choice=7. A choice question [52]Box[7]=Checkbox,6,89.62619pt,758.29315pt,9.95845pt,9.95845pt,box,1.00374pt,7_1,1 [53]Box[7]=Checkbox,6,99.58463pt,758.29315pt,9.95845pt,9.95845pt,box,2.00749pt,7_2,2 [54]Box[7]=Checkbox,6,89.62619pt,744.69315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,7_3,3 [55]Box[7]=Checkbox,6,99.58463pt,744.69315pt,9.95845pt,9.95845pt,ellipse,2.00749pt,7_4,4 [56]Box[7]=Checkbox,6,89.62619pt,731.09314pt,9.95845pt,9.95845pt,box,1.00374pt,7_5,5 [57]Box[7]=Checkbox,6,99.58463pt,731.09314pt,9.95845pt,9.95845pt,box,2.00749pt,7_6,6 [58]Box[7]=Checkbox,6,89.62619pt,717.49313pt,9.95845pt,9.95845pt,ellipse,1.00374pt,7_7,7 [59]Box[7]=Checkbox,6,99.58463pt,717.49313pt,9.95845pt,9.95845pt,ellipse,2.00749pt,7_8,8 [60]Variable[7]=7 [61]Pages=6 ] ============================================================ ============================================================ TEST 8: multichoice/singlechoice switching ============================================================ ** Code 128 ** input: testqid encoded: \startB ,84,69,83,84,81,73,68,67,\stop , black-white: 21121412411211221411421212411212114214211214122114112223311120 ** Code 128 ** input: 324989230007 encoded: \startC ,32,49,89,23,00,07,18,\stop , black-white: 21123223212121133121214131213121222212231222321123311120 [7 [62]QObject-Choice=8. A choice question [63]Box[8]=Checkbox,7,89.62619pt,758.29315pt,9.95845pt,9.95845pt,box,1.00374pt,8_1,1 [64]Box[8]=Checkbox,7,99.58463pt,758.29315pt,9.95845pt,9.95845pt,box,2.00749pt,8_2,2 [65]Box[8]=Checkbox,7,89.62619pt,744.69315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,8_3,3 [66]Box[8]=Checkbox,7,99.58463pt,744.69315pt,9.95845pt,9.95845pt,ellipse,2.00749pt,8_4,4 [67]Box[8]=Checkbox,7,89.62619pt,731.09314pt,9.95845pt,9.95845pt,box,1.00374pt,8_5,5 [68]Box[8]=Checkbox,7,99.58463pt,731.09314pt,9.95845pt,9.95845pt,box,1.00374pt,8_6,6 [69]Box[8]=Checkbox,7,89.62619pt,717.49313pt,9.95845pt,9.95845pt,ellipse,1.00374pt,8_7,7 [70]Box[8]=Checkbox,7,99.58463pt,717.49313pt,9.95845pt,9.95845pt,ellipse,2.00749pt,8_8,8 [71]Variable[8]=8 [72]Pages=7 ] ============================================================ ============================================================ TEST 9: Checkbox overlays ============================================================ ** Code 128 ** input: testqid encoded: \startB ,84,69,83,84,81,73,68,67,\stop , black-white: 21121412411211221411421212411212114214211214122114112223311120 ** Code 128 ** input: 324989230008 encoded: \startC ,32,49,89,23,00,08,24,\stop , black-white: 21123223212121133121214131213121222213221231122223311120 [8 [73]QObject-Choice=9. A choice question [74]Box[9]=Checkbox,8,89.62619pt,758.29315pt,9.95845pt,9.95845pt,box,1.00374pt,9_1,1 POSITION X: 5930953,49123996 [75]Box[9]=Checkbox,8,89.62619pt,738.08757pt,9.95845pt,9.95845pt,box,1.00374pt,9_2,2 [76]Box[9]=Checkbox,8,103.23462pt,740.22153pt,14.22636pt,14.22636pt,box,1.00374pt,9_3,3 [77]Box[9]=Checkbox,8,121.11096pt,740.22153pt,28.45274pt,14.22636pt,box,1.00374pt,9_4,4 [78]Box[9]=Checkbox,8,153.21368pt,747.33472pt,14.22636pt,28.45274pt,box,1.00374pt,9_5,5 [79]Box[9]=Checkbox,8,89.62619pt,708.63484pt,9.95845pt,9.95845pt,ellipse,1.00374pt,9_6,6 [80]Box[9]=Checkbox,8,103.23462pt,710.7688pt,14.22636pt,14.22636pt,ellipse,1.00374pt,9_7,7 [81]Box[9]=Checkbox,8,121.11096pt,710.7688pt,28.45274pt,14.22636pt,ellipse,1.00374pt,9_8,8 [82]Box[9]=Checkbox,8,153.21368pt,717.88199pt,14.22636pt,28.45274pt,ellipse,1.00374pt,9_9,9 [83]Box[9]=Checkbox,8,89.62619pt,688.42926pt,54.75014pt,43.80011pt,box,1.00374pt,9_10,10 POSITION Minipage: 6005305,44372489 [84]Box[9]=Checkbox,8,148.0263pt,688.42926pt,54.75014pt,43.80011pt,box,1.00374pt,9_11,11 POSITION Minipage: 9832615,44372489 [85]Box[9]=Checkbox,8,89.62619pt,643.62917pt,54.75014pt,43.80011pt,box,1.00374pt,9_12,12 POSITION Minipage: 6005305,42049318 [86]Box[9]=Checkbox,8,148.0263pt,643.62917pt,54.75014pt,43.80011pt,box,1.00374pt,9_13,13 POSITION Minipage: 9832615,42049318 [87]Box[9]=Checkbox,8,89.62619pt,598.82907pt,54.75014pt,43.80011pt,box,1.00374pt,9_14,14 POSITION Minipage: 6005305,37887603 [88]Box[9]=Checkbox,8,148.0263pt,598.82907pt,54.75014pt,43.80011pt,box,1.00374pt,9_15,15 POSITION Minipage: 9832615,37887603 [89]Box[9]=Checkbox,8,89.62619pt,554.02898pt,54.75014pt,43.80011pt,box,1.00374pt,9_16,16 POSITION Minipage: 5873742,35564432 [90]Box[9]=Checkbox,8,148.0263pt,554.02898pt,54.75014pt,43.80011pt,box,1.00374pt,9_17,17 POSITION Minipage: 9701052,35564432 [91]Box[9]=Checkbox,8,89.62619pt,509.22888pt,54.75014pt,43.80011pt,box,1.00374pt,9_18,18 POSITION Minipage: 5873742,33372824 [92]Box[9]=Checkbox,8,148.0263pt,509.22888pt,54.75014pt,43.80011pt,box,1.00374pt,9_19,19 POSITION Minipage: 9701052,33372824 [93]Box[9]=Checkbox,8,89.62619pt,464.42879pt,54.75014pt,43.80011pt,box,1.00374pt,9_20,20 POSITION Minipage: 5873742,28947983 [94]Box[9]=Checkbox,8,148.0263pt,464.42879pt,54.75014pt,43.80011pt,box,1.00374pt,9_21,21 POSITION Minipage: 9701052,28947983 [95]Variable[9]=9 [96]Pages=8 ] ============================================================ ============================================================ TEST 10: Finish the SDAPS document, only modifies global state ============================================================ ============================================================ ============================================================ TEST 11: Flush out the last page (writes the page number) ============================================================ ============================================================ (base.aux) sdaps-1.9.8/tex/class/testfiles/base.xetex.tlg0000644000175000000660000002777413600505201022075 0ustar benjaminlock00000000000000This is a generated file for the l3build validation system. Don't change this file in any respect. ============================================================ Setting overrides throws no errors ============================================================ ============================================================ ============================================================ TEST 1: Initialize SDAPS ============================================================ ** Code 128 ** input: 324989230001 encoded: \startC ,32,49,89,23,00,01,85,\stop , black-white: 21123223212121133121214131213121222222212212421123311120 [1 [1]Duplex=false [2]PrintQuestionnaireId=0 [3]PageSize=597.50793pt,845.04694pt [4]Style=code128 [5]CheckMode=checkcorrect [6]GlobalID= [7]GlobalIDLabel= ] ============================================================ ============================================================ TEST 2: Test nested unwrapping of context scopes ============================================================ ============================================================ ============================================================ TEST 3: Check metadata error handling ============================================================ Package sdapsbase Warning: Trying to output metadata but no question ID is set (sdapsbase) on the context. Did you start a question? (sdapsbase) Supressing the output! ** Code 128 ** input: 324989230002 encoded: \startC ,32,49,89,23,00,02,91,\stop , black-white: 21123223212121133121214131213121222222222141212123311120 [2 [8]QObject-Choice=2. A choice question [9]Box[2]=Checkbox,2,89.62619pt,731.09705pt,9.95845pt,9.95845pt,box,1.00374pt,2_1,1 [10]Variable[2]=2 [11]Pages=2 ] ============================================================ ============================================================ TEST 4: Check whether overrides and variable generation are working ============================================================ ** Code 128 ** input: testqid encoded: \startB ,84,69,83,84,81,73,68,67,\stop , black-white: 21121412411211221411421212411212114214211214122114112223311120 ** Code 128 ** input: 324989230003 encoded: \startC ,32,49,89,23,00,03,97,\stop , black-white: 21123223212121133121214131213121222212122341111323311120 [3 [12]QObject-Choice=3. A choice question [13]Box[3]=Checkbox,3,89.62619pt,746.31589pt,9.95845pt,14.22636pt,box,1.00374pt,3_1,1 [14]Box[3]=Checkbox,3,103.23097pt,753.42908pt,9.95845pt,28.45274pt,box,1.00374pt,testvar,2 [15]Box[3]=Checkbox,3,116.83575pt,756.98567pt,9.95845pt,35.56593pt,box,1.00374pt,3_testvar,3 [16]Box[3]=Checkbox,3,130.44054pt,760.54227pt,9.95845pt,42.67912pt,box,1.00374pt,testvar,testval [17]Variable[3]=3 [18]QObject-Choice=4. A choice question [19]Box[4]=Checkbox,3,89.62619pt,705.48206pt,9.95845pt,19.91692pt,box,1.00374pt,prefix_1,1 [20]Box[4]=Checkbox,3,103.23097pt,709.74997pt,9.95845pt,28.45274pt,box,1.00374pt,prefix_testvar,2 [21]Box[4]=Checkbox,3,116.83575pt,709.74997pt,9.95845pt,28.45274pt,box,1.00374pt,prefix_testvar,3 [22]Box[4]=Checkbox,3,130.44054pt,716.86316pt,9.95845pt,42.67912pt,box,1.00374pt,prefix_testvar,testval [23]Variable[4]=prefix [24]Pages=3 ] ============================================================ ============================================================ TEST 5: Check whether context appending is working ============================================================ ** Code 128 ** input: testqid encoded: \startB ,84,69,83,84,81,73,68,67,\stop , black-white: 21121412411211221411421212411212114214211214122114112223311120 ** Code 128 ** input: 324989230004 encoded: \startC ,32,49,89,23,00,04,0,\stop , black-white: 21123223212121133121214131213121222212132221222223311120 [4 [25]QObject-Choice=5. A choice question [26]Box[5]=Checkbox,4,100.57619pt,753.42908pt,9.95845pt,14.22636pt,box,1.00374pt,5_1,1 [27]Box[5]=Checkbox,4,114.18097pt,760.54227pt,9.95845pt,28.45274pt,box,1.00374pt,5_2,2 [28]Variable[5]=5 [29]Pages=4 ] ============================================================ ============================================================ TEST 6: Check different checkbox designs and font sizes ============================================================ ** Code 128 ** input: testqid encoded: \startB ,84,69,83,84,81,73,68,67,\stop , black-white: 21121412411211221411421212411212114214211214122114112223311120 ** Code 128 ** input: 324989230005 encoded: \startC ,32,49,89,23,00,05,6,\stop , black-white: 21123223212121133121214131213121222213122212221323311120 [5 [30]QObject-Choice=6. A choice question [31]Box[6]=Checkbox,5,159.8442pt,756.59029pt,9.95845pt,9.95845pt,box,1.00374pt,6_1,1 [32]Box[6]=Checkbox,5,170.8182pt,727.27989pt,9.95845pt,9.95845pt,box,1.00374pt,6_2,2 [33]Box[6]=Checkbox,5,178.05121pt,697.62468pt,9.95845pt,9.95845pt,box,1.00374pt,6_3,3 [34]Box[6]=Checkbox,5,185.2262pt,667.96948pt,9.95845pt,9.95845pt,box,1.00374pt,6_4,4 [35]Box[6]=Checkbox,5,194.30817pt,638.29706pt,9.95845pt,9.95845pt,box,1.00374pt,6_5,5 [36]Box[6]=Checkbox,5,201.89821pt,608.65909pt,9.95845pt,9.95845pt,box,1.00374pt,6_6,6 [37]Box[6]=Checkbox,5,224.35254pt,579.4866pt,9.95845pt,9.95845pt,box,1.00374pt,6_7,7 [38]Box[6]=Checkbox,5,271.24644pt,551.67267pt,9.95845pt,9.95845pt,box,1.00374pt,6_8,8 [39]Box[6]=Checkbox,5,307.50041pt,523.10013pt,9.95845pt,9.95845pt,box,1.00374pt,6_9,9 [40]Box[6]=Checkbox,5,159.8442pt,486.59029pt,9.95845pt,9.95845pt,ellipse,1.00374pt,6_10,10 [41]Box[6]=Checkbox,5,170.8182pt,457.27989pt,9.95845pt,9.95845pt,ellipse,1.00374pt,6_11,11 [42]Box[6]=Checkbox,5,178.05121pt,427.62468pt,9.95845pt,9.95845pt,ellipse,1.00374pt,6_12,12 [43]Box[6]=Checkbox,5,185.2262pt,397.96948pt,9.95845pt,9.95845pt,ellipse,1.00374pt,6_13,13 [44]Box[6]=Checkbox,5,194.30817pt,368.29706pt,9.95845pt,9.95845pt,ellipse,1.00374pt,6_14,14 [45]Box[6]=Checkbox,5,201.89821pt,338.65909pt,9.95845pt,9.95845pt,ellipse,1.00374pt,6_15,15 [46]Box[6]=Checkbox,5,224.35254pt,309.4866pt,9.95845pt,9.95845pt,ellipse,1.00374pt,6_16,16 [47]Box[6]=Checkbox,5,271.24644pt,281.67267pt,9.95845pt,9.95845pt,ellipse,1.00374pt,6_17,17 [48]Box[6]=Checkbox,5,307.50041pt,253.10013pt,9.95845pt,9.95845pt,ellipse,1.00374pt,6_18,18 [49]Variable[6]=6 [50]Pages=5 ] ============================================================ ============================================================ TEST 7: Checkbox line width, form and fill setting ============================================================ ** Code 128 ** input: testqid encoded: \startB ,84,69,83,84,81,73,68,67,\stop , black-white: 21121412411211221411421212411212114214211214122114112223311120 ** Code 128 ** input: 324989230006 encoded: \startC ,32,49,89,23,00,06,12,\stop , black-white: 21123223212121133121214131213121222212221311223223311120 [6 [51]QObject-Choice=7. A choice question [52]Box[7]=Checkbox,6,89.62619pt,758.29706pt,9.95845pt,9.95845pt,box,1.00374pt,7_1,1 [53]Box[7]=Checkbox,6,99.58463pt,758.29706pt,9.95845pt,9.95845pt,box,2.00749pt,7_2,2 [54]Box[7]=Checkbox,6,89.62619pt,744.69705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,7_3,3 [55]Box[7]=Checkbox,6,99.58463pt,744.69705pt,9.95845pt,9.95845pt,ellipse,2.00749pt,7_4,4 [56]Box[7]=Checkbox,6,89.62619pt,731.09705pt,9.95845pt,9.95845pt,box,1.00374pt,7_5,5 [57]Box[7]=Checkbox,6,99.58463pt,731.09705pt,9.95845pt,9.95845pt,box,2.00749pt,7_6,6 [58]Box[7]=Checkbox,6,89.62619pt,717.49704pt,9.95845pt,9.95845pt,ellipse,1.00374pt,7_7,7 [59]Box[7]=Checkbox,6,99.58463pt,717.49704pt,9.95845pt,9.95845pt,ellipse,2.00749pt,7_8,8 [60]Variable[7]=7 [61]Pages=6 ] ============================================================ ============================================================ TEST 8: multichoice/singlechoice switching ============================================================ ** Code 128 ** input: testqid encoded: \startB ,84,69,83,84,81,73,68,67,\stop , black-white: 21121412411211221411421212411212114214211214122114112223311120 ** Code 128 ** input: 324989230007 encoded: \startC ,32,49,89,23,00,07,18,\stop , black-white: 21123223212121133121214131213121222212231222321123311120 [7 [62]QObject-Choice=8. A choice question [63]Box[8]=Checkbox,7,89.62619pt,758.29706pt,9.95845pt,9.95845pt,box,1.00374pt,8_1,1 [64]Box[8]=Checkbox,7,99.58463pt,758.29706pt,9.95845pt,9.95845pt,box,2.00749pt,8_2,2 [65]Box[8]=Checkbox,7,89.62619pt,744.69705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,8_3,3 [66]Box[8]=Checkbox,7,99.58463pt,744.69705pt,9.95845pt,9.95845pt,ellipse,2.00749pt,8_4,4 [67]Box[8]=Checkbox,7,89.62619pt,731.09705pt,9.95845pt,9.95845pt,box,1.00374pt,8_5,5 [68]Box[8]=Checkbox,7,99.58463pt,731.09705pt,9.95845pt,9.95845pt,box,1.00374pt,8_6,6 [69]Box[8]=Checkbox,7,89.62619pt,717.49704pt,9.95845pt,9.95845pt,ellipse,1.00374pt,8_7,7 [70]Box[8]=Checkbox,7,99.58463pt,717.49704pt,9.95845pt,9.95845pt,ellipse,2.00749pt,8_8,8 [71]Variable[8]=8 [72]Pages=7 ] ============================================================ ============================================================ TEST 9: Checkbox overlays ============================================================ ** Code 128 ** input: testqid encoded: \startB ,84,69,83,84,81,73,68,67,\stop , black-white: 21121412411211221411421212411212114214211214122114112223311120 ** Code 128 ** input: 324989230008 encoded: \startC ,32,49,89,23,00,08,24,\stop , black-white: 21123223212121133121214131213121222213221231122223311120 [8 [73]QObject-Choice=9. A choice question [74]Box[9]=Checkbox,8,89.62619pt,758.29706pt,9.95845pt,9.95845pt,box,1.00374pt,9_1,1 POSITION X: 5873742,49043119 [75]Box[9]=Checkbox,8,89.62619pt,738.09148pt,9.95845pt,9.95845pt,box,1.00374pt,9_2,2 [76]Box[9]=Checkbox,8,103.23097pt,740.22543pt,14.22636pt,14.22636pt,box,1.00374pt,9_3,3 [77]Box[9]=Checkbox,8,121.10367pt,740.22543pt,28.45274pt,14.22636pt,box,1.00374pt,9_4,4 [78]Box[9]=Checkbox,8,153.20274pt,747.33862pt,14.22636pt,28.45274pt,box,1.00374pt,9_5,5 [79]Box[9]=Checkbox,8,89.62619pt,708.63875pt,9.95845pt,9.95845pt,ellipse,1.00374pt,9_6,6 [80]Box[9]=Checkbox,8,103.23097pt,710.7727pt,14.22636pt,14.22636pt,ellipse,1.00374pt,9_7,7 [81]Box[9]=Checkbox,8,121.10367pt,710.7727pt,28.45274pt,14.22636pt,ellipse,1.00374pt,9_8,8 [82]Box[9]=Checkbox,8,153.20274pt,717.8859pt,14.22636pt,28.45274pt,ellipse,1.00374pt,9_9,9 [83]Box[9]=Checkbox,8,89.62619pt,688.43317pt,54.74998pt,43.79999pt,box,1.00374pt,9_10,10 POSITION Minipage: 5873742,41637663 [84]Box[9]=Checkbox,8,148.0225pt,688.43317pt,54.74998pt,43.79999pt,box,1.00374pt,9_11,11 POSITION Minipage: 9700803,41637663 [85]Box[9]=Checkbox,8,89.62619pt,643.6332pt,54.74998pt,43.79999pt,box,1.00374pt,9_12,12 POSITION Minipage: 5873742,39310669 [86]Box[9]=Checkbox,8,148.0225pt,643.6332pt,54.74998pt,43.79999pt,box,1.00374pt,9_13,13 POSITION Minipage: 9700803,39310669 [87]Box[9]=Checkbox,8,89.62619pt,598.83322pt,54.74998pt,43.79999pt,box,1.00374pt,9_14,14 POSITION Minipage: 5873742,35148732 [88]Box[9]=Checkbox,8,148.0225pt,598.83322pt,54.74998pt,43.79999pt,box,1.00374pt,9_15,15 POSITION Minipage: 9700803,35148732 [89]Box[9]=Checkbox,8,89.62619pt,554.03325pt,54.74998pt,43.79999pt,box,1.00374pt,9_16,16 POSITION Minipage: 5873742,32698067 [90]Box[9]=Checkbox,8,148.0225pt,554.03325pt,54.74998pt,43.79999pt,box,1.00374pt,9_17,17 POSITION Minipage: 9700803,32698067 [91]Box[9]=Checkbox,8,89.62619pt,509.23328pt,54.74998pt,43.79999pt,box,1.00374pt,9_18,18 POSITION Minipage: 5873742,30502636 [92]Box[9]=Checkbox,8,148.0225pt,509.23328pt,54.74998pt,43.79999pt,box,1.00374pt,9_19,19 POSITION Minipage: 9700803,30502636 [93]Box[9]=Checkbox,8,89.62619pt,464.4333pt,54.74998pt,43.79999pt,box,1.00374pt,9_20,20 POSITION Minipage: 5873742,26077573 [94]Box[9]=Checkbox,8,148.0225pt,464.4333pt,54.74998pt,43.79999pt,box,1.00374pt,9_21,21 POSITION Minipage: 9700803,26077573 [95]Variable[9]=9 [96]Pages=8 ] ============================================================ ============================================================ TEST 10: Finish the SDAPS document, only modifies global state ============================================================ ============================================================ ============================================================ TEST 11: Flush out the last page (writes the page number) ============================================================ ============================================================ (base.aux) sdaps-1.9.8/tex/class/testfiles/classic.lvt0000644000175000000660000000724113600505201021452 0ustar benjaminlock00000000000000\documentclass{sdapsclassic} \input{regression-test} \OMIT \def\logpos#1{\lognamedpos{#1}#1} \def\lognamedpos#1{\leavevmode\pdfsavepos\write128{POSITION #1: \the\pdflastxpos,\the\pdflastypos}} \newenvironment{MYTEST}[1]{% \begingroup% \global\advance \gTESTint 1 % \SEPARATOR% \LONGTYPEOUT{% TEST \the\gTESTint: \detokenize{#1}}% \SEPARATOR% }{% \SEPARATOR% \LONGTYPEOUT{}% \endgroup% } \newenvironment{OMITPAGE}{% \begingroup% \OMIT% }{% \vfil\break% \TIMO% \endgroup% } \newenvironment{MYTESTPAGE}[1]{% \begin{MYTEST}{#1}% }{% \vfil\break% \end{MYTEST}% } \newenvironment{MYTESTPAGESHOW}[1]{% \begin{MYTESTPAGE}{#1}% \showoutput% }{% \end{MYTESTPAGE}% } \author{} \title{} \chead[header]{header} \cfoot[footer to disable qr code]{footer to disable qr code} \begin{document} \ExplSyntaxOn % Redirect output to log file instead of .sdaps file \iow_close:N \g_sdaps_infofile_iow \global\let\g_sdaps_infofile_iow=\c_log_iow \ExplSyntaxOff \begin{questionnaire}[noinfo] % Some font stuff $ a + b $ \textbackslash \vfil\break \TIMO \START \begin{MYTESTPAGE}{singlemark} \singlemark{question}{lower}{upper} \singlemark[count=7]{question}{lower}{upper} \singlemarkother[count=7]{question}{lower}{upper}{other} \end{MYTESTPAGE} \begin{MYTESTPAGE}{choicequestion} \begin{choicequestion}[cols=7]{Question} \choiceitem{a} \choiceitem[var=b,text=btext]{b} \choicemulticolitem[text=ctext]{2}{c} \choiceitemtext[text=dtext]{3cm}{3}{d} \end{choicequestion} \begin{choicequestion}[cols=7,var=qvar,singlechoice]{Question} \choiceitem{a} \choiceitem[val=10,text=btext]{b} \choicemulticolitem[text=ctext]{3}{c} \choicemulticolitem[text=ctext]{3}{c} \end{choicequestion} % Here we test that baselineskip correctly works on the last baseline of the row \begin{choicequestion}[cols=7]{Question} \baselineskip=2em \choiceitem{a \newline a} \choicemulticolitem{6}{b} \choiceitem{c} \choicemulticolitem{6}{d \newline d} \choiceitem{e} \choicemulticolitem{6}{g} \choiceitem{g} \choiceitemtext{2cm}{6}{h} \choiceitem{e} \choicemulticolitem{6}{\newline g} \choiceitem{g} \choiceitemtext{2cm}{6}{h} \end{choicequestion} \end{MYTESTPAGE} \begin{MYTESTPAGE}{choicegroup} \begin{choicegroup}{Inline Header} \groupaddchoice{a} \choice{b} \choiceline{qa} \question{qb} \end{choicegroup} \begin{choicegroup}[text=Metadata Header]{Replaced Header} \choice{a} \choice{b} \question{qa} \question{qb} \end{choicegroup} \begin{choicegroup}[var=test]{Header} \choice{a} \choice[var=b]{b} \choice{c} \question{qa} \question[var=b]{qb} \question{qc} \end{choicegroup} \end{MYTESTPAGE} \begin{MYTESTPAGE}{optiongroup} \begin{optiongroup}{Inline Header} \groupaddchoice{a} \choice{b} \optionline{qa} \question{qb} \end{optiongroup} \begin{optiongroup}[text=Metadata Header]{Replaced Header} \choice{a} \choice{b} \question{qa} \question{qb} \end{optiongroup} \begin{optiongroup}[var=test]{Header} \choice{a} \choice[var=b]{b} \choice{c} \question{qa} \question[var=b]{qb} \question{qc} \end{optiongroup} \end{MYTESTPAGE} \begin{MYTESTPAGE}{markgroup} \begin{markgroup}{Inline Header} \range{a}{lower}{upper} \range{b}{lower}{upper} \markline{c}{l}{u} \end{markgroup} \begin{markgroup}[other,var=a]{Inline Header} \range{a}{lower}{upper}{other} \range[var=b]{b}{lower}{upper}{other} \markline{c}{l}{u}{other} \end{markgroup} \end{MYTESTPAGE} \OMIT \end{questionnaire} \end{document} \TIMO sdaps-1.9.8/tex/class/testfiles/classic.tlg0000644000175000000660000004543313600505201021440 0ustar benjaminlock00000000000000This is a generated file for the l3build validation system. Don't change this file in any respect. ============================================================ TEST 1: singlemark ============================================================ Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding): (hyperref) removing `\unhcopy' on input line .... Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding): (hyperref) removing `\strutbox' on input line .... Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding): (hyperref) removing `\unhcopy' on input line .... Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding): (hyperref) removing `\strutbox' on input line .... Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding): (hyperref) removing `\unhcopy' on input line .... Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding): (hyperref) removing `\strutbox' on input line .... [2 [10]QObject-Head=0. [11]QObject-range=0.1. question [12]Range-lower[0.1]=0,lower [13]Range-upper[0.1]=4,upper [24]Box[0.1]=Checkbox,0,249.85786pt,762.1402pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_1_1,1 [25]Box[0.1]=Checkbox,0,271.81631pt,762.1402pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_1_2,2 [26]Box[0.1]=Checkbox,0,293.77477pt,762.1402pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_1_3,3 [27]Box[0.1]=Checkbox,0,315.73322pt,762.1402pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_1_4,4 [28]Box[0.1]=Checkbox,0,337.69167pt,762.1402pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_1_5,5 [29]Variable[0.1]=0_1 [30]QObject-range=0.2. question [31]Range-lower[0.2]=0,lower [32]Range-upper[0.2]=6,upper [47]Box[0.2]=Checkbox,0,227.89941pt,722.13914pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_2_1,1 [48]Box[0.2]=Checkbox,0,249.85786pt,722.13914pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_2_2,2 [49]Box[0.2]=Checkbox,0,271.81631pt,722.13914pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_2_3,3 [50]Box[0.2]=Checkbox,0,293.77477pt,722.13914pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_2_4,4 [51]Box[0.2]=Checkbox,0,315.73322pt,722.13914pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_2_5,5 [52]Box[0.2]=Checkbox,0,337.69167pt,722.13914pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_2_6,6 [53]Box[0.2]=Checkbox,0,359.65012pt,722.13914pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_2_7,7 [54]Variable[0.2]=0_2 [55]QObject-range=0.3. question [56]Range-lower[0.3]=0,lower [57]Range-upper[0.3]=6,upper [58]Answer[0.3]=other [75]Box[0.3]=Checkbox,0,165.31404pt,682.13809pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_3_1,1 [76]Box[0.3]=Checkbox,0,187.27249pt,682.13809pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_3_2,2 [77]Box[0.3]=Checkbox,0,209.23094pt,682.13809pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_3_3,3 [78]Box[0.3]=Checkbox,0,231.18939pt,682.13809pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_3_4,4 [79]Box[0.3]=Checkbox,0,253.14784pt,682.13809pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_3_5,5 [80]Box[0.3]=Checkbox,0,275.1063pt,682.13809pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_3_6,6 [81]Box[0.3]=Checkbox,0,297.06474pt,682.13809pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_3_7,7 [82]Box[0.3]=Checkbox,0,444.19391pt,682.13809pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_3_0,0 [83]Variable[0.3]=0_3 ] ============================================================ ============================================================ TEST 2: choicequestion ============================================================ Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding): (hyperref) removing `\unhcopy' on input line .... Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding): (hyperref) removing `\strutbox' on input line .... Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding): (hyperref) removing `\unhcopy' on input line .... Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding): (hyperref) removing `\strutbox' on input line .... Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding): (hyperref) removing `\unhcopy' on input line .... Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding): (hyperref) removing `\strutbox' on input line .... [3 [84]QObject-Choice=0.4. Question [85]Answer[0.4]=a [87]Answer[0.4]=btext [89]Answer[0.4]=ctext [91]Answer[0.4]=dtext [86]Box[0.4]=Checkbox,0,40.1433pt,725.2103pt,9.95845pt,9.95845pt,box,1.00374pt,0_4_1,1 [88]Box[0.4]=Checkbox,0,116.41968pt,725.2103pt,9.95845pt,9.95845pt,box,1.00374pt,b,2 [90]Box[0.4]=Checkbox,0,192.69606pt,725.2103pt,9.95845pt,9.95845pt,box,1.00374pt,0_4_3,3 [92]Box[0.4]=Textbox,0,354.92775pt,762.91019pt,202.43684pt,85.35825pt,1.00374pt,0_4_4, [93]Variable[0.4]=0_4 [94]QObject-Option=0.5. Question [95]Answer[0.5]=a [97]Answer[0.5]=btext [99]Answer[0.5]=ctext [101]Answer[0.5]=ctext [96]Box[0.5]=Checkbox,0,40.1433pt,645.68501pt,9.95845pt,9.95845pt,ellipse,1.00374pt,qvar_1,1 [98]Box[0.5]=Checkbox,0,116.41968pt,645.68501pt,9.95845pt,9.95845pt,ellipse,1.00374pt,qvar_2,10 [100]Box[0.5]=Checkbox,0,192.69606pt,645.68501pt,9.95845pt,9.95845pt,ellipse,1.00374pt,qvar_3,3 [102]Box[0.5]=Checkbox,0,40.1433pt,632.085pt,9.95845pt,9.95845pt,ellipse,1.00374pt,qvar_4,4 [103]Variable[0.5]=qvar [104]QObject-Choice=0.6. Question [105]Answer[0.6]=a \newline a [107]Answer[0.6]=b [109]Answer[0.6]=c [106]Box[0.6]=Checkbox,0,40.1433pt,580.21231pt,9.95845pt,9.95845pt,box,1.00374pt,0_6_1,1 [108]Box[0.6]=Checkbox,0,116.41968pt,580.21231pt,9.95845pt,9.95845pt,box,1.00374pt,0_6_2,2 [111]Answer[0.6]=d \newline d [113]Answer[0.6]=e [110]Box[0.6]=Checkbox,0,40.1433pt,544.83655pt,9.95845pt,9.95845pt,box,1.00374pt,0_6_3,3 [112]Box[0.6]=Checkbox,0,116.41968pt,544.83655pt,9.95845pt,9.95845pt,box,1.00374pt,0_6_4,4 [115]Answer[0.6]=g [117]Answer[0.6]=g [114]Box[0.6]=Checkbox,0,40.1433pt,509.46078pt,9.95845pt,9.95845pt,box,1.00374pt,0_6_5,5 [116]Box[0.6]=Checkbox,0,116.41968pt,509.46078pt,9.95845pt,9.95845pt,box,1.00374pt,0_6_6,6 [119]Answer[0.6]=h [121]Answer[0.6]=e [118]Box[0.6]=Checkbox,0,40.1433pt,472.15727pt,9.95845pt,9.95845pt,box,1.00374pt,0_6_7,7 [120]Box[0.6]=Textbox,0,126.0986pt,495.63078pt,431.26604pt,56.90549pt,1.00374pt,0_6_8, [123]Answer[0.6]=\newline g [125]Answer[0.6]=g [122]Box[0.6]=Checkbox,0,40.1433pt,436.9553pt,9.95845pt,9.95845pt,box,1.00374pt,0_6_9,9 [124]Box[0.6]=Checkbox,0,116.41968pt,436.9553pt,9.95845pt,9.95845pt,box,1.00374pt,0_6_10,10 [127]Answer[0.6]=h [126]Box[0.6]=Checkbox,0,40.1433pt,386.05179pt,9.95845pt,9.95845pt,box,1.00374pt,0_6_11,11 [128]Box[0.6]=Textbox,0,126.0986pt,409.5253pt,431.26604pt,56.90549pt,1.00374pt,0_6_12, [129]Variable[0.6]=0_6 ] ============================================================ ============================================================ TEST 3: choicegroup ============================================================ Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding): (hyperref) removing `\unhcopy' on input line .... Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding): (hyperref) removing `\strutbox' on input line .... Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding): (hyperref) removing `\unhcopy' on input line .... Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding): (hyperref) removing `\strutbox' on input line .... Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding): (hyperref) removing `\unhcopy' on input line .... Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding): (hyperref) removing `\strutbox' on input line .... [4 [130]QObject-Head=0.7. Inline Header [131]QObject-Choice=0.7.1. qa [132]Answer[0.7.1]=a [133]Answer[0.7.1]=b [134]Box[0.7.1]=Checkbox,0,525.44777pt,754.25359pt,9.95845pt,9.95845pt,box,1.00374pt,0_7_1_1,1 [135]Box[0.7.1]=Checkbox,0,547.4062pt,754.25359pt,9.95845pt,9.95845pt,box,1.00374pt,0_7_1_2,2 [136]Variable[0.7.1]=0_7_1 [137]QObject-Choice=0.7.2. qb [138]Answer[0.7.2]=a [139]Answer[0.7.2]=b [140]Box[0.7.2]=Checkbox,0,525.44777pt,740.65358pt,9.95845pt,9.95845pt,box,1.00374pt,0_7_2_1,1 [141]Box[0.7.2]=Checkbox,0,547.4062pt,740.65358pt,9.95845pt,9.95845pt,box,1.00374pt,0_7_2_2,2 [142]Variable[0.7.2]=0_7_2 [143]Variable[0.7]=0_7 [144]QObject-Head=0.8. Metadata Header [145]QObject-Choice=0.8.1. qa [146]Answer[0.8.1]=a [147]Answer[0.8.1]=b [148]Box[0.8.1]=Checkbox,0,525.44777pt,692.78345pt,9.95845pt,9.95845pt,box,1.00374pt,0_8_1_1,1 [149]Box[0.8.1]=Checkbox,0,547.4062pt,692.78345pt,9.95845pt,9.95845pt,box,1.00374pt,0_8_1_2,2 [150]Variable[0.8.1]=0_8_1 [151]QObject-Choice=0.8.2. qb [152]Answer[0.8.2]=a [153]Answer[0.8.2]=b [154]Box[0.8.2]=Checkbox,0,525.44777pt,679.18344pt,9.95845pt,9.95845pt,box,1.00374pt,0_8_2_1,1 [155]Box[0.8.2]=Checkbox,0,547.4062pt,679.18344pt,9.95845pt,9.95845pt,box,1.00374pt,0_8_2_2,2 [156]Variable[0.8.2]=0_8_2 [157]Variable[0.8]=0_8 [158]QObject-Head=0.9. Header [159]QObject-Choice=0.9.1. qa [160]Answer[0.9.1]=a [161]Answer[0.9.1]=b [162]Answer[0.9.1]=c [163]Box[0.9.1]=Checkbox,0,503.48933pt,631.31331pt,9.95845pt,9.95845pt,box,1.00374pt,test_1_1,1 [164]Box[0.9.1]=Checkbox,0,525.44777pt,631.31331pt,9.95845pt,9.95845pt,box,1.00374pt,test_1_b,2 [165]Box[0.9.1]=Checkbox,0,547.4062pt,631.31331pt,9.95845pt,9.95845pt,box,1.00374pt,test_1_3,3 [166]Variable[0.9.1]=test_1 [167]QObject-Choice=0.9.2. qb [168]Answer[0.9.2]=a [169]Answer[0.9.2]=b [170]Answer[0.9.2]=c [171]Box[0.9.2]=Checkbox,0,503.48933pt,617.7133pt,9.95845pt,9.95845pt,box,1.00374pt,test_b_1,1 [172]Box[0.9.2]=Checkbox,0,525.44777pt,617.7133pt,9.95845pt,9.95845pt,box,1.00374pt,test_b_b,2 [173]Box[0.9.2]=Checkbox,0,547.4062pt,617.7133pt,9.95845pt,9.95845pt,box,1.00374pt,test_b_3,3 [174]Variable[0.9.2]=test_b [175]QObject-Choice=0.9.3. qc [176]Answer[0.9.3]=a [177]Answer[0.9.3]=b [178]Answer[0.9.3]=c [179]Box[0.9.3]=Checkbox,0,503.48933pt,604.1133pt,9.95845pt,9.95845pt,box,1.00374pt,test_3_1,1 [180]Box[0.9.3]=Checkbox,0,525.44777pt,604.1133pt,9.95845pt,9.95845pt,box,1.00374pt,test_3_b,2 [181]Box[0.9.3]=Checkbox,0,547.4062pt,604.1133pt,9.95845pt,9.95845pt,box,1.00374pt,test_3_3,3 [182]Variable[0.9.3]=test_3 [183]Variable[0.9]=test ] ============================================================ ============================================================ TEST 4: optiongroup ============================================================ Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding): (hyperref) removing `\unhcopy' on input line .... Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding): (hyperref) removing `\strutbox' on input line .... Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding): (hyperref) removing `\unhcopy' on input line .... Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding): (hyperref) removing `\strutbox' on input line .... Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding): (hyperref) removing `\unhcopy' on input line .... Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding): (hyperref) removing `\strutbox' on input line .... [5 [184]QObject-Head=0.10. Inline Header [185]QObject-Option=0.10.1. qa [186]Answer[0.10.1]=a [187]Answer[0.10.1]=b [188]Box[0.10.1]=Checkbox,0,525.44777pt,754.25359pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_10_1_1,1 [189]Box[0.10.1]=Checkbox,0,547.4062pt,754.25359pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_10_1_2,2 [190]Variable[0.10.1]=0_10_1 [191]QObject-Option=0.10.2. qb [192]Answer[0.10.2]=a [193]Answer[0.10.2]=b [194]Box[0.10.2]=Checkbox,0,525.44777pt,740.65358pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_10_2_1,1 [195]Box[0.10.2]=Checkbox,0,547.4062pt,740.65358pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_10_2_2,2 [196]Variable[0.10.2]=0_10_2 [197]Variable[0.10]=0_10 [198]QObject-Head=0.11. Metadata Header [199]QObject-Option=0.11.1. qa [200]Answer[0.11.1]=a [201]Answer[0.11.1]=b [202]Box[0.11.1]=Checkbox,0,525.44777pt,692.78345pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_11_1_1,1 [203]Box[0.11.1]=Checkbox,0,547.4062pt,692.78345pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_11_1_2,2 [204]Variable[0.11.1]=0_11_1 [205]QObject-Option=0.11.2. qb [206]Answer[0.11.2]=a [207]Answer[0.11.2]=b [208]Box[0.11.2]=Checkbox,0,525.44777pt,679.18344pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_11_2_1,1 [209]Box[0.11.2]=Checkbox,0,547.4062pt,679.18344pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_11_2_2,2 [210]Variable[0.11.2]=0_11_2 [211]Variable[0.11]=0_11 [212]QObject-Head=0.12. Header [213]QObject-Option=0.12.1. qa [214]Answer[0.12.1]=a [215]Answer[0.12.1]=b [216]Answer[0.12.1]=c [217]Box[0.12.1]=Checkbox,0,503.48933pt,631.31331pt,9.95845pt,9.95845pt,ellipse,1.00374pt,test_1_1,1 [218]Box[0.12.1]=Checkbox,0,525.44777pt,631.31331pt,9.95845pt,9.95845pt,ellipse,1.00374pt,test_1_b,2 [219]Box[0.12.1]=Checkbox,0,547.4062pt,631.31331pt,9.95845pt,9.95845pt,ellipse,1.00374pt,test_1_3,3 [220]Variable[0.12.1]=test_1 [221]QObject-Option=0.12.2. qb [222]Answer[0.12.2]=a [223]Answer[0.12.2]=b [224]Answer[0.12.2]=c [225]Box[0.12.2]=Checkbox,0,503.48933pt,617.7133pt,9.95845pt,9.95845pt,ellipse,1.00374pt,test_b_1,1 [226]Box[0.12.2]=Checkbox,0,525.44777pt,617.7133pt,9.95845pt,9.95845pt,ellipse,1.00374pt,test_b_b,2 [227]Box[0.12.2]=Checkbox,0,547.4062pt,617.7133pt,9.95845pt,9.95845pt,ellipse,1.00374pt,test_b_3,3 [228]Variable[0.12.2]=test_b [229]QObject-Option=0.12.3. qc [230]Answer[0.12.3]=a [231]Answer[0.12.3]=b [232]Answer[0.12.3]=c [233]Box[0.12.3]=Checkbox,0,503.48933pt,604.1133pt,9.95845pt,9.95845pt,ellipse,1.00374pt,test_3_1,1 [234]Box[0.12.3]=Checkbox,0,525.44777pt,604.1133pt,9.95845pt,9.95845pt,ellipse,1.00374pt,test_3_b,2 [235]Box[0.12.3]=Checkbox,0,547.4062pt,604.1133pt,9.95845pt,9.95845pt,ellipse,1.00374pt,test_3_3,3 [236]Variable[0.12.3]=test_3 [237]Variable[0.12]=test ] ============================================================ ============================================================ TEST 5: markgroup ============================================================ Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding): (hyperref) removing `\unhcopy' on input line .... Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding): (hyperref) removing `\strutbox' on input line .... Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding): (hyperref) removing `\unhcopy' on input line .... Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding): (hyperref) removing `\strutbox' on input line .... [6 [238]QObject-Head=0.13. Inline Header [239]QObject-Range=0.13.1. a [240]Range-lower[0.13.1]=0,lower [241]Box[0.13.1]=Checkbox,0,424.49905pt,767.85359pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_13_1_1,1 [242]Box[0.13.1]=Checkbox,0,445.34537pt,767.85359pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_13_1_2,2 [243]Box[0.13.1]=Checkbox,0,466.19168pt,767.85359pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_13_1_3,3 [244]Box[0.13.1]=Checkbox,0,487.038pt,767.85359pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_13_1_4,4 [245]Box[0.13.1]=Checkbox,0,507.88431pt,767.85359pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_13_1_5,5 [246]Range-upper[0.13.1]=4,upper [247]Variable[0.13.1]=0_13_1 [248]QObject-Range=0.13.2. b [249]Range-lower[0.13.2]=0,lower [250]Box[0.13.2]=Checkbox,0,424.49905pt,754.25359pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_13_2_1,1 [251]Box[0.13.2]=Checkbox,0,445.34537pt,754.25359pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_13_2_2,2 [252]Box[0.13.2]=Checkbox,0,466.19168pt,754.25359pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_13_2_3,3 [253]Box[0.13.2]=Checkbox,0,487.038pt,754.25359pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_13_2_4,4 [254]Box[0.13.2]=Checkbox,0,507.88431pt,754.25359pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_13_2_5,5 [255]Range-upper[0.13.2]=4,upper [256]Variable[0.13.2]=0_13_2 [257]QObject-Range=0.13.3. c [258]Range-lower[0.13.3]=0,l [259]Box[0.13.3]=Checkbox,0,424.49905pt,740.65358pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_13_3_1,1 [260]Box[0.13.3]=Checkbox,0,445.34537pt,740.65358pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_13_3_2,2 [261]Box[0.13.3]=Checkbox,0,466.19168pt,740.65358pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_13_3_3,3 [262]Box[0.13.3]=Checkbox,0,487.038pt,740.65358pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_13_3_4,4 [263]Box[0.13.3]=Checkbox,0,507.88431pt,740.65358pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_13_3_5,5 [264]Range-upper[0.13.3]=4,u [265]Variable[0.13.3]=0_13_3 [266]Variable[0.13]=0_13 [267]QObject-Head=0.14. Inline Header [268]QObject-Range=0.14.1. a [269]Range-lower[0.14.1]=0,lower [270]Box[0.14.1]=Checkbox,0,362.10823pt,706.38345pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_1_1,1 [271]Box[0.14.1]=Checkbox,0,382.95454pt,706.38345pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_1_2,2 [272]Box[0.14.1]=Checkbox,0,403.80086pt,706.38345pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_1_3,3 [273]Box[0.14.1]=Checkbox,0,424.64717pt,706.38345pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_1_4,4 [274]Box[0.14.1]=Checkbox,0,445.49348pt,706.38345pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_1_5,5 [275]Range-upper[0.14.1]=4,upper [276]Answer[0.14.1]=other [277]Box[0.14.1]=Checkbox,0,518.97382pt,706.38345pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_1_6,0 [278]Variable[0.14.1]=a_1 [279]QObject-Range=0.14.2. b [280]Range-lower[0.14.2]=0,lower [281]Box[0.14.2]=Checkbox,0,362.10823pt,692.78345pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_b_1,1 [282]Box[0.14.2]=Checkbox,0,382.95454pt,692.78345pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_b_2,2 [283]Box[0.14.2]=Checkbox,0,403.80086pt,692.78345pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_b_3,3 [284]Box[0.14.2]=Checkbox,0,424.64717pt,692.78345pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_b_4,4 [285]Box[0.14.2]=Checkbox,0,445.49348pt,692.78345pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_b_5,5 [286]Range-upper[0.14.2]=4,upper [287]Answer[0.14.2]=other [288]Box[0.14.2]=Checkbox,0,518.97382pt,692.78345pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_b_6,0 [289]Variable[0.14.2]=a_b [290]QObject-Range=0.14.3. c [291]Range-lower[0.14.3]=0,l [292]Box[0.14.3]=Checkbox,0,362.10823pt,679.18344pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_3_1,1 [293]Box[0.14.3]=Checkbox,0,382.95454pt,679.18344pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_3_2,2 [294]Box[0.14.3]=Checkbox,0,403.80086pt,679.18344pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_3_3,3 [295]Box[0.14.3]=Checkbox,0,424.64717pt,679.18344pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_3_4,4 [296]Box[0.14.3]=Checkbox,0,445.49348pt,679.18344pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_3_5,5 [297]Range-upper[0.14.3]=4,u [298]Answer[0.14.3]=other [299]Box[0.14.3]=Checkbox,0,518.97382pt,679.18344pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_3_6,0 [300]Variable[0.14.3]=a_3 [301]Variable[0.14]=a ] ============================================================ sdaps-1.9.8/tex/class/testfiles/classic.xetex.tlg0000644000175000000660000004516113600505201022572 0ustar benjaminlock00000000000000This is a generated file for the l3build validation system. Don't change this file in any respect. ============================================================ TEST 1: singlemark ============================================================ Package hyperref Warning: Token not allowed in a PDF string (Unicode): (hyperref) removing `\unhcopy' on input line .... Package hyperref Warning: Token not allowed in a PDF string (Unicode): (hyperref) removing `\strutbox' on input line .... Package hyperref Warning: Token not allowed in a PDF string (Unicode): (hyperref) removing `\unhcopy' on input line .... Package hyperref Warning: Token not allowed in a PDF string (Unicode): (hyperref) removing `\strutbox' on input line .... Package hyperref Warning: Token not allowed in a PDF string (Unicode): (hyperref) removing `\unhcopy' on input line .... Package hyperref Warning: Token not allowed in a PDF string (Unicode): (hyperref) removing `\strutbox' on input line .... [2 [10]QObject-Head=0. [11]QObject-range=0.1. question [12]Range-lower[0.1]=0,lower [13]Range-upper[0.1]=4,upper [24]Box[0.1]=Checkbox,0,249.85786pt,762.13997pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_1_1,1 [25]Box[0.1]=Checkbox,0,271.81631pt,762.13997pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_1_2,2 [26]Box[0.1]=Checkbox,0,293.77477pt,762.13997pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_1_3,3 [27]Box[0.1]=Checkbox,0,315.73322pt,762.13997pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_1_4,4 [28]Box[0.1]=Checkbox,0,337.69167pt,762.13997pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_1_5,5 [29]Variable[0.1]=0_1 [30]QObject-range=0.2. question [31]Range-lower[0.2]=0,lower [32]Range-upper[0.2]=6,upper [47]Box[0.2]=Checkbox,0,227.89941pt,722.13617pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_2_1,1 [48]Box[0.2]=Checkbox,0,249.85786pt,722.13617pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_2_2,2 [49]Box[0.2]=Checkbox,0,271.81631pt,722.13617pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_2_3,3 [50]Box[0.2]=Checkbox,0,293.77477pt,722.13617pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_2_4,4 [51]Box[0.2]=Checkbox,0,315.73322pt,722.13617pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_2_5,5 [52]Box[0.2]=Checkbox,0,337.69167pt,722.13617pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_2_6,6 [53]Box[0.2]=Checkbox,0,359.65012pt,722.13617pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_2_7,7 [54]Variable[0.2]=0_2 [55]QObject-range=0.3. question [56]Range-lower[0.3]=0,lower [57]Range-upper[0.3]=6,upper [58]Answer[0.3]=other [75]Box[0.3]=Checkbox,0,165.31404pt,682.13237pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_3_1,1 [76]Box[0.3]=Checkbox,0,187.27249pt,682.13237pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_3_2,2 [77]Box[0.3]=Checkbox,0,209.23094pt,682.13237pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_3_3,3 [78]Box[0.3]=Checkbox,0,231.18939pt,682.13237pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_3_4,4 [79]Box[0.3]=Checkbox,0,253.14784pt,682.13237pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_3_5,5 [80]Box[0.3]=Checkbox,0,275.1063pt,682.13237pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_3_6,6 [81]Box[0.3]=Checkbox,0,297.06474pt,682.13237pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_3_7,7 [82]Box[0.3]=Checkbox,0,444.19391pt,682.13237pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_3_0,0 [83]Variable[0.3]=0_3 ] ============================================================ ============================================================ TEST 2: choicequestion ============================================================ Package hyperref Warning: Token not allowed in a PDF string (Unicode): (hyperref) removing `\unhcopy' on input line .... Package hyperref Warning: Token not allowed in a PDF string (Unicode): (hyperref) removing `\strutbox' on input line .... Package hyperref Warning: Token not allowed in a PDF string (Unicode): (hyperref) removing `\unhcopy' on input line .... Package hyperref Warning: Token not allowed in a PDF string (Unicode): (hyperref) removing `\strutbox' on input line .... Package hyperref Warning: Token not allowed in a PDF string (Unicode): (hyperref) removing `\unhcopy' on input line .... Package hyperref Warning: Token not allowed in a PDF string (Unicode): (hyperref) removing `\strutbox' on input line .... [3 [84]QObject-Choice=0.4. Question [85]Answer[0.4]=a [87]Answer[0.4]=btext [89]Answer[0.4]=ctext [91]Answer[0.4]=dtext [86]Box[0.4]=Checkbox,0,40.1433pt,725.2092pt,9.95845pt,9.95845pt,box,1.00374pt,0_4_1,1 [88]Box[0.4]=Checkbox,0,116.41985pt,725.2092pt,9.95845pt,9.95845pt,box,1.00374pt,b,2 [90]Box[0.4]=Checkbox,0,192.6964pt,725.2092pt,9.95845pt,9.95845pt,box,1.00374pt,0_4_3,3 [92]Box[0.4]=Textbox,0,354.98274pt,762.90909pt,202.3819pt,85.35825pt,1.00374pt,0_4_4, [93]Variable[0.4]=0_4 [94]QObject-Option=0.5. Question [95]Answer[0.5]=a [97]Answer[0.5]=btext [99]Answer[0.5]=ctext [101]Answer[0.5]=ctext [96]Box[0.5]=Checkbox,0,40.1433pt,645.68094pt,9.95845pt,9.95845pt,ellipse,1.00374pt,qvar_1,1 [98]Box[0.5]=Checkbox,0,116.41985pt,645.68094pt,9.95845pt,9.95845pt,ellipse,1.00374pt,qvar_2,10 [100]Box[0.5]=Checkbox,0,192.6964pt,645.68094pt,9.95845pt,9.95845pt,ellipse,1.00374pt,qvar_3,3 [102]Box[0.5]=Checkbox,0,40.1433pt,632.08093pt,9.95845pt,9.95845pt,ellipse,1.00374pt,qvar_4,4 [103]Variable[0.5]=qvar [104]QObject-Choice=0.6. Question [105]Answer[0.6]=a \newline a [107]Answer[0.6]=b [109]Answer[0.6]=c [106]Box[0.6]=Checkbox,0,40.1433pt,580.08015pt,9.95845pt,9.95845pt,box,1.00374pt,0_6_1,1 [108]Box[0.6]=Checkbox,0,116.41985pt,580.08015pt,9.95845pt,9.95845pt,box,1.00374pt,0_6_2,2 [111]Answer[0.6]=d \newline d [113]Answer[0.6]=e [110]Box[0.6]=Checkbox,0,40.1433pt,544.58015pt,9.95845pt,9.95845pt,box,1.00374pt,0_6_3,3 [112]Box[0.6]=Checkbox,0,116.41985pt,544.58015pt,9.95845pt,9.95845pt,box,1.00374pt,0_6_4,4 [115]Answer[0.6]=g [117]Answer[0.6]=g [114]Box[0.6]=Checkbox,0,40.1433pt,509.08015pt,9.95845pt,9.95845pt,box,1.00374pt,0_6_5,5 [116]Box[0.6]=Checkbox,0,116.41985pt,509.08015pt,9.95845pt,9.95845pt,box,1.00374pt,0_6_6,6 [119]Answer[0.6]=h [121]Answer[0.6]=e [118]Box[0.6]=Checkbox,0,40.1433pt,471.77577pt,9.95845pt,9.95845pt,box,1.00374pt,0_6_7,7 [120]Box[0.6]=Textbox,0,126.15309pt,495.24928pt,431.21155pt,56.90549pt,1.00374pt,0_6_8, [123]Answer[0.6]=\newline g [125]Answer[0.6]=g [122]Box[0.6]=Checkbox,0,40.1433pt,436.57468pt,9.95845pt,9.95845pt,box,1.00374pt,0_6_9,9 [124]Box[0.6]=Checkbox,0,116.41985pt,436.57468pt,9.95845pt,9.95845pt,box,1.00374pt,0_6_10,10 [127]Answer[0.6]=h [126]Box[0.6]=Checkbox,0,40.1433pt,385.67029pt,9.95845pt,9.95845pt,box,1.00374pt,0_6_11,11 [128]Box[0.6]=Textbox,0,126.15309pt,409.1438pt,431.21155pt,56.90549pt,1.00374pt,0_6_12, [129]Variable[0.6]=0_6 ] ============================================================ ============================================================ TEST 3: choicegroup ============================================================ Package hyperref Warning: Token not allowed in a PDF string (Unicode): (hyperref) removing `\unhcopy' on input line .... Package hyperref Warning: Token not allowed in a PDF string (Unicode): (hyperref) removing `\strutbox' on input line .... Package hyperref Warning: Token not allowed in a PDF string (Unicode): (hyperref) removing `\unhcopy' on input line .... Package hyperref Warning: Token not allowed in a PDF string (Unicode): (hyperref) removing `\strutbox' on input line .... Package hyperref Warning: Token not allowed in a PDF string (Unicode): (hyperref) removing `\unhcopy' on input line .... Package hyperref Warning: Token not allowed in a PDF string (Unicode): (hyperref) removing `\strutbox' on input line .... [4 [130]QObject-Head=0.7. Inline Header [131]QObject-Choice=0.7.1. qa [132]Answer[0.7.1]=a [133]Answer[0.7.1]=b [134]Box[0.7.1]=Checkbox,0,525.44777pt,754.25446pt,9.95845pt,9.95845pt,box,1.00374pt,0_7_1_1,1 [135]Box[0.7.1]=Checkbox,0,547.4062pt,754.25446pt,9.95845pt,9.95845pt,box,1.00374pt,0_7_1_2,2 [136]Variable[0.7.1]=0_7_1 [137]QObject-Choice=0.7.2. qb [138]Answer[0.7.2]=a [139]Answer[0.7.2]=b [140]Box[0.7.2]=Checkbox,0,525.44777pt,740.65445pt,9.95845pt,9.95845pt,box,1.00374pt,0_7_2_1,1 [141]Box[0.7.2]=Checkbox,0,547.4062pt,740.65445pt,9.95845pt,9.95845pt,box,1.00374pt,0_7_2_2,2 [142]Variable[0.7.2]=0_7_2 [143]Variable[0.7]=0_7 [144]QObject-Head=0.8. Metadata Header [145]QObject-Choice=0.8.1. qa [146]Answer[0.8.1]=a [147]Answer[0.8.1]=b [148]Box[0.8.1]=Checkbox,0,525.44777pt,692.78267pt,9.95845pt,9.95845pt,box,1.00374pt,0_8_1_1,1 [149]Box[0.8.1]=Checkbox,0,547.4062pt,692.78267pt,9.95845pt,9.95845pt,box,1.00374pt,0_8_1_2,2 [150]Variable[0.8.1]=0_8_1 [151]QObject-Choice=0.8.2. qb [152]Answer[0.8.2]=a [153]Answer[0.8.2]=b [154]Box[0.8.2]=Checkbox,0,525.44777pt,679.18266pt,9.95845pt,9.95845pt,box,1.00374pt,0_8_2_1,1 [155]Box[0.8.2]=Checkbox,0,547.4062pt,679.18266pt,9.95845pt,9.95845pt,box,1.00374pt,0_8_2_2,2 [156]Variable[0.8.2]=0_8_2 [157]Variable[0.8]=0_8 [158]QObject-Head=0.9. Header [159]QObject-Choice=0.9.1. qa [160]Answer[0.9.1]=a [161]Answer[0.9.1]=b [162]Answer[0.9.1]=c [163]Box[0.9.1]=Checkbox,0,503.48933pt,631.31088pt,9.95845pt,9.95845pt,box,1.00374pt,test_1_1,1 [164]Box[0.9.1]=Checkbox,0,525.44777pt,631.31088pt,9.95845pt,9.95845pt,box,1.00374pt,test_1_b,2 [165]Box[0.9.1]=Checkbox,0,547.4062pt,631.31088pt,9.95845pt,9.95845pt,box,1.00374pt,test_1_3,3 [166]Variable[0.9.1]=test_1 [167]QObject-Choice=0.9.2. qb [168]Answer[0.9.2]=a [169]Answer[0.9.2]=b [170]Answer[0.9.2]=c [171]Box[0.9.2]=Checkbox,0,503.48933pt,617.71088pt,9.95845pt,9.95845pt,box,1.00374pt,test_b_1,1 [172]Box[0.9.2]=Checkbox,0,525.44777pt,617.71088pt,9.95845pt,9.95845pt,box,1.00374pt,test_b_b,2 [173]Box[0.9.2]=Checkbox,0,547.4062pt,617.71088pt,9.95845pt,9.95845pt,box,1.00374pt,test_b_3,3 [174]Variable[0.9.2]=test_b [175]QObject-Choice=0.9.3. qc [176]Answer[0.9.3]=a [177]Answer[0.9.3]=b [178]Answer[0.9.3]=c [179]Box[0.9.3]=Checkbox,0,503.48933pt,604.11087pt,9.95845pt,9.95845pt,box,1.00374pt,test_3_1,1 [180]Box[0.9.3]=Checkbox,0,525.44777pt,604.11087pt,9.95845pt,9.95845pt,box,1.00374pt,test_3_b,2 [181]Box[0.9.3]=Checkbox,0,547.4062pt,604.11087pt,9.95845pt,9.95845pt,box,1.00374pt,test_3_3,3 [182]Variable[0.9.3]=test_3 [183]Variable[0.9]=test ] ============================================================ ============================================================ TEST 4: optiongroup ============================================================ Package hyperref Warning: Token not allowed in a PDF string (Unicode): (hyperref) removing `\unhcopy' on input line .... Package hyperref Warning: Token not allowed in a PDF string (Unicode): (hyperref) removing `\strutbox' on input line .... Package hyperref Warning: Token not allowed in a PDF string (Unicode): (hyperref) removing `\unhcopy' on input line .... Package hyperref Warning: Token not allowed in a PDF string (Unicode): (hyperref) removing `\strutbox' on input line .... Package hyperref Warning: Token not allowed in a PDF string (Unicode): (hyperref) removing `\unhcopy' on input line .... Package hyperref Warning: Token not allowed in a PDF string (Unicode): (hyperref) removing `\strutbox' on input line .... [5 [184]QObject-Head=0.10. Inline Header [185]QObject-Option=0.10.1. qa [186]Answer[0.10.1]=a [187]Answer[0.10.1]=b [188]Box[0.10.1]=Checkbox,0,525.44777pt,754.25446pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_10_1_1,1 [189]Box[0.10.1]=Checkbox,0,547.4062pt,754.25446pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_10_1_2,2 [190]Variable[0.10.1]=0_10_1 [191]QObject-Option=0.10.2. qb [192]Answer[0.10.2]=a [193]Answer[0.10.2]=b [194]Box[0.10.2]=Checkbox,0,525.44777pt,740.65445pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_10_2_1,1 [195]Box[0.10.2]=Checkbox,0,547.4062pt,740.65445pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_10_2_2,2 [196]Variable[0.10.2]=0_10_2 [197]Variable[0.10]=0_10 [198]QObject-Head=0.11. Metadata Header [199]QObject-Option=0.11.1. qa [200]Answer[0.11.1]=a [201]Answer[0.11.1]=b [202]Box[0.11.1]=Checkbox,0,525.44777pt,692.78267pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_11_1_1,1 [203]Box[0.11.1]=Checkbox,0,547.4062pt,692.78267pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_11_1_2,2 [204]Variable[0.11.1]=0_11_1 [205]QObject-Option=0.11.2. qb [206]Answer[0.11.2]=a [207]Answer[0.11.2]=b [208]Box[0.11.2]=Checkbox,0,525.44777pt,679.18266pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_11_2_1,1 [209]Box[0.11.2]=Checkbox,0,547.4062pt,679.18266pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_11_2_2,2 [210]Variable[0.11.2]=0_11_2 [211]Variable[0.11]=0_11 [212]QObject-Head=0.12. Header [213]QObject-Option=0.12.1. qa [214]Answer[0.12.1]=a [215]Answer[0.12.1]=b [216]Answer[0.12.1]=c [217]Box[0.12.1]=Checkbox,0,503.48933pt,631.31088pt,9.95845pt,9.95845pt,ellipse,1.00374pt,test_1_1,1 [218]Box[0.12.1]=Checkbox,0,525.44777pt,631.31088pt,9.95845pt,9.95845pt,ellipse,1.00374pt,test_1_b,2 [219]Box[0.12.1]=Checkbox,0,547.4062pt,631.31088pt,9.95845pt,9.95845pt,ellipse,1.00374pt,test_1_3,3 [220]Variable[0.12.1]=test_1 [221]QObject-Option=0.12.2. qb [222]Answer[0.12.2]=a [223]Answer[0.12.2]=b [224]Answer[0.12.2]=c [225]Box[0.12.2]=Checkbox,0,503.48933pt,617.71088pt,9.95845pt,9.95845pt,ellipse,1.00374pt,test_b_1,1 [226]Box[0.12.2]=Checkbox,0,525.44777pt,617.71088pt,9.95845pt,9.95845pt,ellipse,1.00374pt,test_b_b,2 [227]Box[0.12.2]=Checkbox,0,547.4062pt,617.71088pt,9.95845pt,9.95845pt,ellipse,1.00374pt,test_b_3,3 [228]Variable[0.12.2]=test_b [229]QObject-Option=0.12.3. qc [230]Answer[0.12.3]=a [231]Answer[0.12.3]=b [232]Answer[0.12.3]=c [233]Box[0.12.3]=Checkbox,0,503.48933pt,604.11087pt,9.95845pt,9.95845pt,ellipse,1.00374pt,test_3_1,1 [234]Box[0.12.3]=Checkbox,0,525.44777pt,604.11087pt,9.95845pt,9.95845pt,ellipse,1.00374pt,test_3_b,2 [235]Box[0.12.3]=Checkbox,0,547.4062pt,604.11087pt,9.95845pt,9.95845pt,ellipse,1.00374pt,test_3_3,3 [236]Variable[0.12.3]=test_3 [237]Variable[0.12]=test ] ============================================================ ============================================================ TEST 5: markgroup ============================================================ Package hyperref Warning: Token not allowed in a PDF string (Unicode): (hyperref) removing `\unhcopy' on input line .... Package hyperref Warning: Token not allowed in a PDF string (Unicode): (hyperref) removing `\strutbox' on input line .... Package hyperref Warning: Token not allowed in a PDF string (Unicode): (hyperref) removing `\unhcopy' on input line .... Package hyperref Warning: Token not allowed in a PDF string (Unicode): (hyperref) removing `\strutbox' on input line .... [6 [238]QObject-Head=0.13. Inline Header [239]QObject-Range=0.13.1. a [240]Range-lower[0.13.1]=0,lower [241]Box[0.13.1]=Checkbox,0,424.06308pt,767.85446pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_13_1_1,1 [242]Box[0.13.1]=Checkbox,0,444.97151pt,767.85446pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_13_1_2,2 [243]Box[0.13.1]=Checkbox,0,465.87994pt,767.85446pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_13_1_3,3 [244]Box[0.13.1]=Checkbox,0,486.78838pt,767.85446pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_13_1_4,4 [245]Box[0.13.1]=Checkbox,0,507.69681pt,767.85446pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_13_1_5,5 [246]Range-upper[0.13.1]=4,upper [247]Variable[0.13.1]=0_13_1 [248]QObject-Range=0.13.2. b [249]Range-lower[0.13.2]=0,lower [250]Box[0.13.2]=Checkbox,0,424.06308pt,754.25446pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_13_2_1,1 [251]Box[0.13.2]=Checkbox,0,444.97151pt,754.25446pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_13_2_2,2 [252]Box[0.13.2]=Checkbox,0,465.87994pt,754.25446pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_13_2_3,3 [253]Box[0.13.2]=Checkbox,0,486.78838pt,754.25446pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_13_2_4,4 [254]Box[0.13.2]=Checkbox,0,507.69681pt,754.25446pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_13_2_5,5 [255]Range-upper[0.13.2]=4,upper [256]Variable[0.13.2]=0_13_2 [257]QObject-Range=0.13.3. c [258]Range-lower[0.13.3]=0,l [259]Box[0.13.3]=Checkbox,0,424.06308pt,740.65445pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_13_3_1,1 [260]Box[0.13.3]=Checkbox,0,444.97151pt,740.65445pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_13_3_2,2 [261]Box[0.13.3]=Checkbox,0,465.87994pt,740.65445pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_13_3_3,3 [262]Box[0.13.3]=Checkbox,0,486.78838pt,740.65445pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_13_3_4,4 [263]Box[0.13.3]=Checkbox,0,507.69681pt,740.65445pt,9.95845pt,9.95845pt,ellipse,1.00374pt,0_13_3_5,5 [264]Range-upper[0.13.3]=4,u [265]Variable[0.13.3]=0_13_3 [266]Variable[0.13]=0_13 [267]QObject-Head=0.14. Inline Header [268]QObject-Range=0.14.1. a [269]Range-lower[0.14.1]=0,lower [270]Box[0.14.1]=Checkbox,0,361.48248pt,706.38268pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_1_1,1 [271]Box[0.14.1]=Checkbox,0,382.39091pt,706.38268pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_1_2,2 [272]Box[0.14.1]=Checkbox,0,403.29935pt,706.38268pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_1_3,3 [273]Box[0.14.1]=Checkbox,0,424.20778pt,706.38268pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_1_4,4 [274]Box[0.14.1]=Checkbox,0,445.11621pt,706.38268pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_1_5,5 [275]Range-upper[0.14.1]=4,upper [276]Answer[0.14.1]=other [277]Box[0.14.1]=Checkbox,0,518.78404pt,706.38268pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_1_6,0 [278]Variable[0.14.1]=a_1 [279]QObject-Range=0.14.2. b [280]Range-lower[0.14.2]=0,lower [281]Box[0.14.2]=Checkbox,0,361.48248pt,692.78267pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_b_1,1 [282]Box[0.14.2]=Checkbox,0,382.39091pt,692.78267pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_b_2,2 [283]Box[0.14.2]=Checkbox,0,403.29935pt,692.78267pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_b_3,3 [284]Box[0.14.2]=Checkbox,0,424.20778pt,692.78267pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_b_4,4 [285]Box[0.14.2]=Checkbox,0,445.11621pt,692.78267pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_b_5,5 [286]Range-upper[0.14.2]=4,upper [287]Answer[0.14.2]=other [288]Box[0.14.2]=Checkbox,0,518.78404pt,692.78267pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_b_6,0 [289]Variable[0.14.2]=a_b [290]QObject-Range=0.14.3. c [291]Range-lower[0.14.3]=0,l [292]Box[0.14.3]=Checkbox,0,361.48248pt,679.18266pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_3_1,1 [293]Box[0.14.3]=Checkbox,0,382.39091pt,679.18266pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_3_2,2 [294]Box[0.14.3]=Checkbox,0,403.29935pt,679.18266pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_3_3,3 [295]Box[0.14.3]=Checkbox,0,424.20778pt,679.18266pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_3_4,4 [296]Box[0.14.3]=Checkbox,0,445.11621pt,679.18266pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_3_5,5 [297]Range-upper[0.14.3]=4,u [298]Answer[0.14.3]=other [299]Box[0.14.3]=Checkbox,0,518.78404pt,679.18266pt,9.95845pt,9.95845pt,ellipse,1.00374pt,a_3_6,0 [300]Variable[0.14.3]=a_3 [301]Variable[0.14]=a ] ============================================================ sdaps-1.9.8/tex/class/testfiles/layout.lvt0000644000175000000660000001416113600505201021345 0ustar benjaminlock00000000000000\documentclass{scrartcl} \input{regression-test} \OMIT \usepackage{sdapslayout} \usepackage{multicol} \def\logpos#1{\lognamedpos{#1}#1} \def\lognamedpos#1{\leavevmode\pdfsavepos\write128{POSITION #1: \the\pdflastxpos,\the\pdflastypos}} \newenvironment{MYTEST}[1]{% \begingroup% \global\advance \gTESTint 1 % \SEPARATOR% \LONGTYPEOUT{% TEST \the\gTESTint: \detokenize{#1}}% \SEPARATOR% }{% \SEPARATOR% \LONGTYPEOUT{}% \endgroup% } \newenvironment{OMITPAGE}{% \begingroup% \OMIT% }{% \vfil\break% \TIMO% \endgroup% } \newenvironment{MYTESTPAGE}[1]{% \begin{MYTEST}{#1}% }{% \vfil\break% \end{MYTEST}% } \newenvironment{MYTESTPAGESHOW}[1]{% \begin{MYTESTPAGE}{#1}% \showoutput% }{% \end{MYTESTPAGE}% } \TIMO \begin{document} \START \begin{OMITPAGE} % Some font stuff $ a + b $ \textbackslash % Open some extra temporary files \begin{sdapsarray} a & b & c \\ d & e & f \end{sdapsarray} % Enable writing out information. \ExplSyntaxOn % Redirect output to log file instead of .sdaps file \iow_close:N \g_sdaps_infofile_iow \global\let\g_sdaps_infofile_iow=\c_log_iow % Enable position writing \sdaps_context_enable_writing: \ExplSyntaxOff \end{OMITPAGE} \begin{MYTESTPAGE}{Basic choicearray} \begin{choicearray}[noalign] \choice{a} \choice{b} \choice{c} \question{qa} \question{qb} \question{qc} \end{choicearray} \end{MYTESTPAGE} \begin{MYTESTPAGE}{Basic singlechoice choicearray} \begin{choicearray}[noalign,singlechoice] \choice{a} \choice{b} \choice{c} \question{qa} \question{qb} \question{qc} \end{choicearray} \end{MYTESTPAGE} \begin{MYTESTPAGE}{choicearray range filtering} \begin{choicearray}[noalign] \choice{a} \choice{b} \choice{c} \question[range={...,2}]{start-2} \question[range={2,...}]{2-end} \question[range={1,...,2}]{1-2} \question[range={1,3}]{1 and 3} \question[range={...,1,3}]{range to 1 and 3} \question[range={1,2,...}]{1 and 2 plus end} \end{choicearray} \begin{choicearray}[noalign,type=multichoice] \choice[var=a]{a} \choice[var=b]{b} \choice[var=c]{c} \question[range={...,b}]{start-2} \question[range={b,...}]{2-end} \question[range={a,...,b}]{1-2} \question[range={a,c}]{1 and 3} \question[range={...,a,c}]{range to 1 and 3} \question[range={a,b,...}]{1 and 2 plus end} \end{choicearray} \end{MYTESTPAGE} \begin{MYTESTPAGE}{choicearray range filtering for singlechoice} \begin{choicearray}[noalign,singlechoice] \choice{a} \choice{b} \choice{c} \question[range={...,2}]{start-2} \question[range={2,...}]{2-end} \question[range={1,...,2}]{1-2} \question[range={1,3}]{1 and 3} \question[range={...,1,3}]{range to 1 and 3} \question[range={1,2,...}]{1 and 2 plus end} \end{choicearray} \begin{choicearray}[noalign,type=singlechoice] \choice[val=11]{a} \choice[val=12]{b} \choice[val=13]{c} \question[range={...,12}]{start-2} \question[range={12,...}]{2-end} \question[range={11,...,12}]{1-2} \question[range={11,13}]{1 and 3} \question[range={...,11,13}]{range to 1 and 3} \question[range={11,12,...}]{1 and 2 plus end} \end{choicearray} \end{MYTESTPAGE} \begin{MYTESTPAGE}{choicearray with fragile content} \begin{choicearray}[noalign] \choice[text=verbatim]{\verb^verbatim^} \choice{b} \choice{c} \question[text=qa]{\verb^qa^} \question{qb} \question{qc} \end{choicearray} \end{MYTESTPAGE} \begin{MYTESTPAGE}{choicearray with variables in different places} \begin{choicearray}[noalign] \choice{a} \choice[var=ab]{b} \choice{c} \question{qa} \question[var=qb]{qb} \question{qc} \end{choicearray} \end{MYTESTPAGE} \begin{MYTESTPAGE}{vertical choicearray} \begin{choicearray}[noalign,vertical] \choice[text=verbatim]{\verb^verbatim^} \choice{b} \choice{c} \question[text=qa]{\verb^qa^} \question[range={2}]{qb only 2} \question{qc} \end{choicearray} \end{MYTESTPAGE} \begin{MYTESTPAGE}{choicearray alignment} \begin{choicearray}[align=choicearray] \choice{long string} \choice{b} \choice{c} \question{qa} \question{qb} \question{qc} \end{choicearray} \begin{choicearray}[align=choicearray] \choice{a} \choice{b} \choice{c} \question{qa} \question{qb} \question{qc} \end{choicearray} \hrule \begin{choicearray}[vertical,align=vertical-choicearray] \choice{a} \choice{b} \choice{c} \question{qa} \question{qb} \question{qc} \end{choicearray} \begin{choicearray}[vertical,align=vertical-choicearray] \choice{a} \choice{b} \choice{c} \question{different long string} \question{qb} \question{qc} \end{choicearray} \hrule \begin{choicearray}[align=aligntest,vertical] \choice{a} \choice{b} \choice{c} \question{yet another long string} \question{qb} \question{qc} \end{choicearray} \begin{choicearray}[align=aligntest] \choice{a} \choice{b} \choice{c} \question{yet another long string} \question{qb} \question{qc} \end{choicearray} \end{MYTESTPAGE} \begin{MYTESTPAGE}{rangearray} \begin{rangearray} \range{qa}{lower}{upper} \range{qb}{lower}{upper} \range[lower=textlower,upper=textupper,text=question text]{\verb^qc^}{\verb^lower^}{\verb^upper^} \end{rangearray} \begin{rangearray}[other] \range{qa}{lower}{upper}{other} \range{qb}{lower}{upper}{other} \range[lower=textlower,upper=textupper,other=textother,text=question text]{\verb^qc^}{\verb^lower^}{\verb^upper^}{\verb^other^} \end{rangearray} \end{MYTESTPAGE} \begin{MYTESTPAGE}{rangearray with variable names} \begin{rangearray} \range{qa}{lower}{upper} \range[var=qb]{qb}{lower}{upper} \range{qc}{lower}{upper} \end{rangearray} \end{MYTESTPAGE} \begin{MYTESTPAGE}{rangearray over multiple columns} \begin{multicols}{2} \begin{rangearray} \range{qa}{l}{u} \range{qb}{l}{u} \range{qc}{l}{u} \range{qd}{l}{u} \end{rangearray} \end{multicols} \end{MYTESTPAGE} \end{document} sdaps-1.9.8/tex/class/testfiles/layout.tlg0000644000175000000660000007105613600505201021334 0ustar benjaminlock00000000000000This is a generated file for the l3build validation system. Don't change this file in any respect. ============================================================ TEST 1: Basic choicearray ============================================================ [2 [1]QObject-Choice=1. qa [2]Answer[1]=a [3]Answer[1]=b [4]Answer[1]=c [5]Box[1]=Checkbox,0,448.00644pt,744.69315pt,9.95845pt,9.95845pt,box,1.00374pt,1_1,1 [6]Box[1]=Checkbox,0,469.96487pt,744.69315pt,9.95845pt,9.95845pt,box,1.00374pt,1_2,2 [7]Box[1]=Checkbox,0,491.92331pt,744.69315pt,9.95845pt,9.95845pt,box,1.00374pt,1_3,3 [8]Variable[1]=1 [9]QObject-Choice=2. qb [10]Answer[2]=a [11]Answer[2]=b [12]Answer[2]=c [13]Box[2]=Checkbox,0,448.00644pt,731.09314pt,9.95845pt,9.95845pt,box,1.00374pt,2_1,1 [14]Box[2]=Checkbox,0,469.96487pt,731.09314pt,9.95845pt,9.95845pt,box,1.00374pt,2_2,2 [15]Box[2]=Checkbox,0,491.92331pt,731.09314pt,9.95845pt,9.95845pt,box,1.00374pt,2_3,3 [16]Variable[2]=2 [17]QObject-Choice=3. qc [18]Answer[3]=a [19]Answer[3]=b [20]Answer[3]=c [21]Box[3]=Checkbox,0,448.00644pt,717.49313pt,9.95845pt,9.95845pt,box,1.00374pt,3_1,1 [22]Box[3]=Checkbox,0,469.96487pt,717.49313pt,9.95845pt,9.95845pt,box,1.00374pt,3_2,2 [23]Box[3]=Checkbox,0,491.92331pt,717.49313pt,9.95845pt,9.95845pt,box,1.00374pt,3_3,3 [24]Variable[3]=3 ] ============================================================ ============================================================ TEST 2: Basic singlechoice choicearray ============================================================ [3 [25]QObject-Option=4. qa [26]Answer[4]=a [27]Answer[4]=b [28]Answer[4]=c [29]Box[4]=Checkbox,0,448.00644pt,744.69315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,4_1,1 [30]Box[4]=Checkbox,0,469.96487pt,744.69315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,4_2,2 [31]Box[4]=Checkbox,0,491.92331pt,744.69315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,4_3,3 [32]Variable[4]=4 [33]QObject-Option=5. qb [34]Answer[5]=a [35]Answer[5]=b [36]Answer[5]=c [37]Box[5]=Checkbox,0,448.00644pt,731.09314pt,9.95845pt,9.95845pt,ellipse,1.00374pt,5_1,1 [38]Box[5]=Checkbox,0,469.96487pt,731.09314pt,9.95845pt,9.95845pt,ellipse,1.00374pt,5_2,2 [39]Box[5]=Checkbox,0,491.92331pt,731.09314pt,9.95845pt,9.95845pt,ellipse,1.00374pt,5_3,3 [40]Variable[5]=5 [41]QObject-Option=6. qc [42]Answer[6]=a [43]Answer[6]=b [44]Answer[6]=c [45]Box[6]=Checkbox,0,448.00644pt,717.49313pt,9.95845pt,9.95845pt,ellipse,1.00374pt,6_1,1 [46]Box[6]=Checkbox,0,469.96487pt,717.49313pt,9.95845pt,9.95845pt,ellipse,1.00374pt,6_2,2 [47]Box[6]=Checkbox,0,491.92331pt,717.49313pt,9.95845pt,9.95845pt,ellipse,1.00374pt,6_3,3 [48]Variable[6]=6 ] ============================================================ ============================================================ TEST 3: choicearray range filtering ============================================================ [4 [49]QObject-Choice=7. start-2 [50]Answer[7]=a [51]Answer[7]=b [52]Box[7]=Checkbox,0,448.00644pt,744.69315pt,9.95845pt,9.95845pt,box,1.00374pt,7_1,1 [53]Box[7]=Checkbox,0,469.96487pt,744.69315pt,9.95845pt,9.95845pt,box,1.00374pt,7_2,2 [54]Variable[7]=7 [55]QObject-Choice=8. 2-end [56]Answer[8]=b [57]Answer[8]=c [58]Box[8]=Checkbox,0,469.96487pt,731.09314pt,9.95845pt,9.95845pt,box,1.00374pt,8_2,2 [59]Box[8]=Checkbox,0,491.92331pt,731.09314pt,9.95845pt,9.95845pt,box,1.00374pt,8_3,3 [60]Variable[8]=8 [61]QObject-Choice=9. 1-2 [62]Answer[9]=a [63]Answer[9]=b [64]Box[9]=Checkbox,0,448.00644pt,717.49313pt,9.95845pt,9.95845pt,box,1.00374pt,9_1,1 [65]Box[9]=Checkbox,0,469.96487pt,717.49313pt,9.95845pt,9.95845pt,box,1.00374pt,9_2,2 [66]Variable[9]=9 [67]QObject-Choice=10. 1 and 3 [68]Answer[10]=a [69]Answer[10]=c [70]Box[10]=Checkbox,0,448.00644pt,703.89313pt,9.95845pt,9.95845pt,box,1.00374pt,10_1,1 [71]Box[10]=Checkbox,0,491.92331pt,703.89313pt,9.95845pt,9.95845pt,box,1.00374pt,10_3,3 [72]Variable[10]=10 [73]QObject-Choice=11. range to 1 and 3 [74]Answer[11]=a [75]Answer[11]=c [76]Box[11]=Checkbox,0,448.00644pt,690.29312pt,9.95845pt,9.95845pt,box,1.00374pt,11_1,1 [77]Box[11]=Checkbox,0,491.92331pt,690.29312pt,9.95845pt,9.95845pt,box,1.00374pt,11_3,3 [78]Variable[11]=11 [79]QObject-Choice=12. 1 and 2 plus end [80]Answer[12]=a [81]Answer[12]=b [82]Answer[12]=c [83]Box[12]=Checkbox,0,448.00644pt,676.69312pt,9.95845pt,9.95845pt,box,1.00374pt,12_1,1 [84]Box[12]=Checkbox,0,469.96487pt,676.69312pt,9.95845pt,9.95845pt,box,1.00374pt,12_2,2 [85]Box[12]=Checkbox,0,491.92331pt,676.69312pt,9.95845pt,9.95845pt,box,1.00374pt,12_3,3 [86]Variable[12]=12 [87]QObject-Choice=13. start-2 [88]Answer[13]=a [89]Answer[13]=b [90]Box[13]=Checkbox,0,448.00644pt,649.4931pt,9.95845pt,9.95845pt,box,1.00374pt,13_a,1 [91]Box[13]=Checkbox,0,469.96487pt,649.4931pt,9.95845pt,9.95845pt,box,1.00374pt,13_b,2 [92]Variable[13]=13 [93]QObject-Choice=14. 2-end [94]Answer[14]=b [95]Answer[14]=c [96]Box[14]=Checkbox,0,469.96487pt,635.8931pt,9.95845pt,9.95845pt,box,1.00374pt,14_b,2 [97]Box[14]=Checkbox,0,491.92331pt,635.8931pt,9.95845pt,9.95845pt,box,1.00374pt,14_c,3 [98]Variable[14]=14 [99]QObject-Choice=15. 1-2 [100]Answer[15]=a [101]Answer[15]=b [102]Box[15]=Checkbox,0,448.00644pt,622.29309pt,9.95845pt,9.95845pt,box,1.00374pt,15_a,1 [103]Box[15]=Checkbox,0,469.96487pt,622.29309pt,9.95845pt,9.95845pt,box,1.00374pt,15_b,2 [104]Variable[15]=15 [105]QObject-Choice=16. 1 and 3 [106]Answer[16]=a [107]Answer[16]=c [108]Box[16]=Checkbox,0,448.00644pt,608.69308pt,9.95845pt,9.95845pt,box,1.00374pt,16_a,1 [109]Box[16]=Checkbox,0,491.92331pt,608.69308pt,9.95845pt,9.95845pt,box,1.00374pt,16_c,3 [110]Variable[16]=16 [111]QObject-Choice=17. range to 1 and 3 [112]Answer[17]=a [113]Answer[17]=c [114]Box[17]=Checkbox,0,448.00644pt,595.09308pt,9.95845pt,9.95845pt,box,1.00374pt,17_a,1 [115]Box[17]=Checkbox,0,491.92331pt,595.09308pt,9.95845pt,9.95845pt,box,1.00374pt,17_c,3 [116]Variable[17]=17 [117]QObject-Choice=18. 1 and 2 plus end [118]Answer[18]=a [119]Answer[18]=b [120]Answer[18]=c [121]Box[18]=Checkbox,0,448.00644pt,581.49307pt,9.95845pt,9.95845pt,box,1.00374pt,18_a,1 [122]Box[18]=Checkbox,0,469.96487pt,581.49307pt,9.95845pt,9.95845pt,box,1.00374pt,18_b,2 [123]Box[18]=Checkbox,0,491.92331pt,581.49307pt,9.95845pt,9.95845pt,box,1.00374pt,18_c,3 [124]Variable[18]=18 ] ============================================================ ============================================================ TEST 4: choicearray range filtering for singlechoice ============================================================ [5 [125]QObject-Option=19. start-2 [126]Answer[19]=a [127]Answer[19]=b [128]Box[19]=Checkbox,0,448.00644pt,744.69315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,19_1,1 [129]Box[19]=Checkbox,0,469.96487pt,744.69315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,19_2,2 [130]Variable[19]=19 [131]QObject-Option=20. 2-end [132]Answer[20]=b [133]Answer[20]=c [134]Box[20]=Checkbox,0,469.96487pt,731.09314pt,9.95845pt,9.95845pt,ellipse,1.00374pt,20_2,2 [135]Box[20]=Checkbox,0,491.92331pt,731.09314pt,9.95845pt,9.95845pt,ellipse,1.00374pt,20_3,3 [136]Variable[20]=20 [137]QObject-Option=21. 1-2 [138]Answer[21]=a [139]Answer[21]=b [140]Box[21]=Checkbox,0,448.00644pt,717.49313pt,9.95845pt,9.95845pt,ellipse,1.00374pt,21_1,1 [141]Box[21]=Checkbox,0,469.96487pt,717.49313pt,9.95845pt,9.95845pt,ellipse,1.00374pt,21_2,2 [142]Variable[21]=21 [143]QObject-Option=22. 1 and 3 [144]Answer[22]=a [145]Answer[22]=c [146]Box[22]=Checkbox,0,448.00644pt,703.89313pt,9.95845pt,9.95845pt,ellipse,1.00374pt,22_1,1 [147]Box[22]=Checkbox,0,491.92331pt,703.89313pt,9.95845pt,9.95845pt,ellipse,1.00374pt,22_3,3 [148]Variable[22]=22 [149]QObject-Option=23. range to 1 and 3 [150]Answer[23]=a [151]Answer[23]=c [152]Box[23]=Checkbox,0,448.00644pt,690.29312pt,9.95845pt,9.95845pt,ellipse,1.00374pt,23_1,1 [153]Box[23]=Checkbox,0,491.92331pt,690.29312pt,9.95845pt,9.95845pt,ellipse,1.00374pt,23_3,3 [154]Variable[23]=23 [155]QObject-Option=24. 1 and 2 plus end [156]Answer[24]=a [157]Answer[24]=b [158]Answer[24]=c [159]Box[24]=Checkbox,0,448.00644pt,676.69312pt,9.95845pt,9.95845pt,ellipse,1.00374pt,24_1,1 [160]Box[24]=Checkbox,0,469.96487pt,676.69312pt,9.95845pt,9.95845pt,ellipse,1.00374pt,24_2,2 [161]Box[24]=Checkbox,0,491.92331pt,676.69312pt,9.95845pt,9.95845pt,ellipse,1.00374pt,24_3,3 [162]Variable[24]=24 [163]QObject-Option=25. start-2 [164]Answer[25]=a [165]Answer[25]=b [166]Box[25]=Checkbox,0,448.00644pt,649.4931pt,9.95845pt,9.95845pt,ellipse,1.00374pt,25_1,11 [167]Box[25]=Checkbox,0,469.96487pt,649.4931pt,9.95845pt,9.95845pt,ellipse,1.00374pt,25_2,12 [168]Variable[25]=25 [169]QObject-Option=26. 2-end [170]Answer[26]=b [171]Answer[26]=c [172]Box[26]=Checkbox,0,469.96487pt,635.8931pt,9.95845pt,9.95845pt,ellipse,1.00374pt,26_2,12 [173]Box[26]=Checkbox,0,491.92331pt,635.8931pt,9.95845pt,9.95845pt,ellipse,1.00374pt,26_3,13 [174]Variable[26]=26 [175]QObject-Option=27. 1-2 [176]Answer[27]=a [177]Answer[27]=b [178]Box[27]=Checkbox,0,448.00644pt,622.29309pt,9.95845pt,9.95845pt,ellipse,1.00374pt,27_1,11 [179]Box[27]=Checkbox,0,469.96487pt,622.29309pt,9.95845pt,9.95845pt,ellipse,1.00374pt,27_2,12 [180]Variable[27]=27 [181]QObject-Option=28. 1 and 3 [182]Answer[28]=a [183]Answer[28]=c [184]Box[28]=Checkbox,0,448.00644pt,608.69308pt,9.95845pt,9.95845pt,ellipse,1.00374pt,28_1,11 [185]Box[28]=Checkbox,0,491.92331pt,608.69308pt,9.95845pt,9.95845pt,ellipse,1.00374pt,28_3,13 [186]Variable[28]=28 [187]QObject-Option=29. range to 1 and 3 [188]Answer[29]=a [189]Answer[29]=c [190]Box[29]=Checkbox,0,448.00644pt,595.09308pt,9.95845pt,9.95845pt,ellipse,1.00374pt,29_1,11 [191]Box[29]=Checkbox,0,491.92331pt,595.09308pt,9.95845pt,9.95845pt,ellipse,1.00374pt,29_3,13 [192]Variable[29]=29 [193]QObject-Option=30. 1 and 2 plus end [194]Answer[30]=a [195]Answer[30]=b [196]Answer[30]=c [197]Box[30]=Checkbox,0,448.00644pt,581.49307pt,9.95845pt,9.95845pt,ellipse,1.00374pt,30_1,11 [198]Box[30]=Checkbox,0,469.96487pt,581.49307pt,9.95845pt,9.95845pt,ellipse,1.00374pt,30_2,12 [199]Box[30]=Checkbox,0,491.92331pt,581.49307pt,9.95845pt,9.95845pt,ellipse,1.00374pt,30_3,13 [200]Variable[30]=30 ] ============================================================ ============================================================ TEST 5: choicearray with fragile content ============================================================ [6 [201]QObject-Choice=31. qa [202]Answer[31]=verbatim [203]Answer[31]=b [204]Answer[31]=c [205]Box[31]=Checkbox,0,429.9909pt,744.69315pt,9.95845pt,9.95845pt,box,1.00374pt,31_1,1 [206]Box[31]=Checkbox,0,469.96487pt,744.69315pt,9.95845pt,9.95845pt,box,1.00374pt,31_2,2 [207]Box[31]=Checkbox,0,491.92331pt,744.69315pt,9.95845pt,9.95845pt,box,1.00374pt,31_3,3 [208]Variable[31]=31 [209]QObject-Choice=32. qb [210]Answer[32]=verbatim [211]Answer[32]=b [212]Answer[32]=c [213]Box[32]=Checkbox,0,429.9909pt,731.09314pt,9.95845pt,9.95845pt,box,1.00374pt,32_1,1 [214]Box[32]=Checkbox,0,469.96487pt,731.09314pt,9.95845pt,9.95845pt,box,1.00374pt,32_2,2 [215]Box[32]=Checkbox,0,491.92331pt,731.09314pt,9.95845pt,9.95845pt,box,1.00374pt,32_3,3 [216]Variable[32]=32 [217]QObject-Choice=33. qc [218]Answer[33]=verbatim [219]Answer[33]=b [220]Answer[33]=c [221]Box[33]=Checkbox,0,429.9909pt,717.49313pt,9.95845pt,9.95845pt,box,1.00374pt,33_1,1 [222]Box[33]=Checkbox,0,469.96487pt,717.49313pt,9.95845pt,9.95845pt,box,1.00374pt,33_2,2 [223]Box[33]=Checkbox,0,491.92331pt,717.49313pt,9.95845pt,9.95845pt,box,1.00374pt,33_3,3 [224]Variable[33]=33 ] ============================================================ ============================================================ TEST 6: choicearray with variables in different places ============================================================ [7 [225]QObject-Choice=34. qa [226]Answer[34]=a [227]Answer[34]=b [228]Answer[34]=c [229]Box[34]=Checkbox,0,448.00644pt,744.69315pt,9.95845pt,9.95845pt,box,1.00374pt,34_1,1 [230]Box[34]=Checkbox,0,469.96487pt,744.69315pt,9.95845pt,9.95845pt,box,1.00374pt,34_ab,2 [231]Box[34]=Checkbox,0,491.92331pt,744.69315pt,9.95845pt,9.95845pt,box,1.00374pt,34_3,3 [232]Variable[34]=34 [233]QObject-Choice=35. qb [234]Answer[35]=a [235]Answer[35]=b [236]Answer[35]=c [237]Box[35]=Checkbox,0,448.00644pt,731.09314pt,9.95845pt,9.95845pt,box,1.00374pt,qb_1,1 [238]Box[35]=Checkbox,0,469.96487pt,731.09314pt,9.95845pt,9.95845pt,box,1.00374pt,qb_ab,2 [239]Box[35]=Checkbox,0,491.92331pt,731.09314pt,9.95845pt,9.95845pt,box,1.00374pt,qb_3,3 [240]Variable[35]=qb [241]QObject-Choice=36. qc [242]Answer[36]=a [243]Answer[36]=b [244]Answer[36]=c [245]Box[36]=Checkbox,0,448.00644pt,717.49313pt,9.95845pt,9.95845pt,box,1.00374pt,36_1,1 [246]Box[36]=Checkbox,0,469.96487pt,717.49313pt,9.95845pt,9.95845pt,box,1.00374pt,36_ab,2 [247]Box[36]=Checkbox,0,491.92331pt,717.49313pt,9.95845pt,9.95845pt,box,1.00374pt,36_3,3 [248]Variable[36]=36 ] ============================================================ ============================================================ TEST 7: vertical choicearray ============================================================ [8 [249]QObject-Choice=37. qa [250]Answer[37]=verbatim [251]Answer[37]=b [252]Answer[37]=c [257]QObject-Choice=38. qb only 2 [258]Answer[38]=b [261]QObject-Choice=39. qc [262]Answer[39]=verbatim [263]Answer[39]=b [264]Answer[39]=c [253]Box[37]=Checkbox,0,411.4913pt,744.69315pt,9.95845pt,9.95845pt,box,1.00374pt,37_1,1 [265]Box[39]=Checkbox,0,491.57962pt,744.69315pt,9.95845pt,9.95845pt,box,1.00374pt,39_1,1 [254]Box[37]=Checkbox,0,411.4913pt,731.09314pt,9.95845pt,9.95845pt,box,1.00374pt,37_2,2 [259]Box[38]=Checkbox,0,451.74835pt,731.09314pt,9.95845pt,9.95845pt,box,1.00374pt,38_2,2 [266]Box[39]=Checkbox,0,491.57962pt,731.09314pt,9.95845pt,9.95845pt,box,1.00374pt,39_2,2 [255]Box[37]=Checkbox,0,411.4913pt,717.49313pt,9.95845pt,9.95845pt,box,1.00374pt,37_3,3 [256]Variable[37]=37 [260]Variable[38]=38 [267]Box[39]=Checkbox,0,491.57962pt,717.49313pt,9.95845pt,9.95845pt,box,1.00374pt,39_3,3 [268]Variable[39]=39 ] ============================================================ ============================================================ TEST 8: choicearray alignment ============================================================ [9 [269]QObject-Choice=40. qa [270]Answer[40]=long string [271]Answer[40]=b [272]Answer[40]=c [273]Box[40]=Checkbox,0,427.39pt,744.69315pt,9.95845pt,9.95845pt,box,1.00374pt,40_1,1 [274]Box[40]=Checkbox,0,469.96487pt,744.69315pt,9.95845pt,9.95845pt,box,1.00374pt,40_2,2 [275]Box[40]=Checkbox,0,491.92331pt,744.69315pt,9.95845pt,9.95845pt,box,1.00374pt,40_3,3 [276]Variable[40]=40 [277]QObject-Choice=41. qb [278]Answer[41]=long string [279]Answer[41]=b [280]Answer[41]=c [281]Box[41]=Checkbox,0,427.39pt,731.09314pt,9.95845pt,9.95845pt,box,1.00374pt,41_1,1 [282]Box[41]=Checkbox,0,469.96487pt,731.09314pt,9.95845pt,9.95845pt,box,1.00374pt,41_2,2 [283]Box[41]=Checkbox,0,491.92331pt,731.09314pt,9.95845pt,9.95845pt,box,1.00374pt,41_3,3 [284]Variable[41]=41 [285]QObject-Choice=42. qc [286]Answer[42]=long string [287]Answer[42]=b [288]Answer[42]=c [289]Box[42]=Checkbox,0,427.39pt,717.49313pt,9.95845pt,9.95845pt,box,1.00374pt,42_1,1 [290]Box[42]=Checkbox,0,469.96487pt,717.49313pt,9.95845pt,9.95845pt,box,1.00374pt,42_2,2 [291]Box[42]=Checkbox,0,491.92331pt,717.49313pt,9.95845pt,9.95845pt,box,1.00374pt,42_3,3 [292]Variable[42]=42 [293]QObject-Choice=43. qa [294]Answer[43]=a [295]Answer[43]=b [296]Answer[43]=c [297]Box[43]=Checkbox,0,427.39pt,690.29312pt,9.95845pt,9.95845pt,box,1.00374pt,43_1,1 [298]Box[43]=Checkbox,0,469.96487pt,690.29312pt,9.95845pt,9.95845pt,box,1.00374pt,43_2,2 [299]Box[43]=Checkbox,0,491.92331pt,690.29312pt,9.95845pt,9.95845pt,box,1.00374pt,43_3,3 [300]Variable[43]=43 [301]QObject-Choice=44. qb [302]Answer[44]=a [303]Answer[44]=b [304]Answer[44]=c [305]Box[44]=Checkbox,0,427.39pt,676.69312pt,9.95845pt,9.95845pt,box,1.00374pt,44_1,1 [306]Box[44]=Checkbox,0,469.96487pt,676.69312pt,9.95845pt,9.95845pt,box,1.00374pt,44_2,2 [307]Box[44]=Checkbox,0,491.92331pt,676.69312pt,9.95845pt,9.95845pt,box,1.00374pt,44_3,3 [308]Variable[44]=44 [309]QObject-Choice=45. qc [310]Answer[45]=a [311]Answer[45]=b [312]Answer[45]=c [313]Box[45]=Checkbox,0,427.39pt,663.09311pt,9.95845pt,9.95845pt,box,1.00374pt,45_1,1 [314]Box[45]=Checkbox,0,469.96487pt,663.09311pt,9.95845pt,9.95845pt,box,1.00374pt,45_2,2 [315]Box[45]=Checkbox,0,491.92331pt,663.09311pt,9.95845pt,9.95845pt,box,1.00374pt,45_3,3 [316]Variable[45]=45 [317]QObject-Choice=46. qa [318]Answer[46]=a [319]Answer[46]=b [320]Answer[46]=c [325]QObject-Choice=47. qb [326]Answer[47]=a [327]Answer[47]=b [328]Answer[47]=c [333]QObject-Choice=48. qc [334]Answer[48]=a [335]Answer[48]=b [336]Answer[48]=c [321]Box[46]=Checkbox,0,403.18748pt,639.35979pt,9.95845pt,9.95845pt,box,1.00374pt,46_1,1 [329]Box[47]=Checkbox,0,468.32545pt,639.35979pt,9.95845pt,9.95845pt,box,1.00374pt,47_1,1 [337]Box[48]=Checkbox,0,491.57962pt,639.35979pt,9.95845pt,9.95845pt,box,1.00374pt,48_1,1 [322]Box[46]=Checkbox,0,403.18748pt,625.75978pt,9.95845pt,9.95845pt,box,1.00374pt,46_2,2 [330]Box[47]=Checkbox,0,468.32545pt,625.75978pt,9.95845pt,9.95845pt,box,1.00374pt,47_2,2 [338]Box[48]=Checkbox,0,491.57962pt,625.75978pt,9.95845pt,9.95845pt,box,1.00374pt,48_2,2 [323]Box[46]=Checkbox,0,403.18748pt,612.15977pt,9.95845pt,9.95845pt,box,1.00374pt,46_3,3 [324]Variable[46]=46 [331]Box[47]=Checkbox,0,468.32545pt,612.15977pt,9.95845pt,9.95845pt,box,1.00374pt,47_3,3 [332]Variable[47]=47 [339]Box[48]=Checkbox,0,491.57962pt,612.15977pt,9.95845pt,9.95845pt,box,1.00374pt,48_3,3 [340]Variable[48]=48 [341]QObject-Choice=49. different long string [342]Answer[49]=a [343]Answer[49]=b [344]Answer[49]=c [349]QObject-Choice=50. qb [350]Answer[50]=a [351]Answer[50]=b [352]Answer[50]=c [357]QObject-Choice=51. qc [358]Answer[51]=a [359]Answer[51]=b [360]Answer[51]=c [345]Box[49]=Checkbox,0,403.18748pt,584.95976pt,9.95845pt,9.95845pt,box,1.00374pt,49_1,1 [353]Box[50]=Checkbox,0,468.32545pt,584.95976pt,9.95845pt,9.95845pt,box,1.00374pt,50_1,1 [361]Box[51]=Checkbox,0,491.57962pt,584.95976pt,9.95845pt,9.95845pt,box,1.00374pt,51_1,1 [346]Box[49]=Checkbox,0,403.18748pt,571.35976pt,9.95845pt,9.95845pt,box,1.00374pt,49_2,2 [354]Box[50]=Checkbox,0,468.32545pt,571.35976pt,9.95845pt,9.95845pt,box,1.00374pt,50_2,2 [362]Box[51]=Checkbox,0,491.57962pt,571.35976pt,9.95845pt,9.95845pt,box,1.00374pt,51_2,2 [347]Box[49]=Checkbox,0,403.18748pt,557.75975pt,9.95845pt,9.95845pt,box,1.00374pt,49_3,3 [348]Variable[49]=49 [355]Box[50]=Checkbox,0,468.32545pt,557.75975pt,9.95845pt,9.95845pt,box,1.00374pt,50_3,3 [356]Variable[50]=50 [363]Box[51]=Checkbox,0,491.57962pt,557.75975pt,9.95845pt,9.95845pt,box,1.00374pt,51_3,3 [364]Variable[51]=51 [365]QObject-Choice=52. yet another long string [366]Answer[52]=a [367]Answer[52]=b [368]Answer[52]=c [373]QObject-Choice=53. qb [374]Answer[53]=a [375]Answer[53]=b [376]Answer[53]=c [381]QObject-Choice=54. qc [382]Answer[54]=a [383]Answer[54]=b [384]Answer[54]=c [369]Box[52]=Checkbox,0,395.5833pt,534.94804pt,9.95845pt,9.95845pt,box,1.00374pt,52_1,1 [377]Box[53]=Checkbox,0,468.32545pt,534.94804pt,9.95845pt,9.95845pt,box,1.00374pt,53_1,1 [385]Box[54]=Checkbox,0,491.57962pt,534.94804pt,9.95845pt,9.95845pt,box,1.00374pt,54_1,1 [370]Box[52]=Checkbox,0,395.5833pt,521.34804pt,9.95845pt,9.95845pt,box,1.00374pt,52_2,2 [378]Box[53]=Checkbox,0,468.32545pt,521.34804pt,9.95845pt,9.95845pt,box,1.00374pt,53_2,2 [386]Box[54]=Checkbox,0,491.57962pt,521.34804pt,9.95845pt,9.95845pt,box,1.00374pt,54_2,2 [371]Box[52]=Checkbox,0,395.5833pt,507.74803pt,9.95845pt,9.95845pt,box,1.00374pt,52_3,3 [372]Variable[52]=52 [379]Box[53]=Checkbox,0,468.32545pt,507.74803pt,9.95845pt,9.95845pt,box,1.00374pt,53_3,3 [380]Variable[53]=53 [387]Box[54]=Checkbox,0,491.57962pt,507.74803pt,9.95845pt,9.95845pt,box,1.00374pt,54_3,3 [388]Variable[54]=54 [389]QObject-Choice=55. yet another long string [390]Answer[55]=a [391]Answer[55]=b [392]Answer[55]=c [393]Box[55]=Checkbox,0,395.5833pt,480.54802pt,9.95845pt,9.95845pt,box,1.00374pt,55_1,1 [394]Box[55]=Checkbox,0,468.32545pt,480.54802pt,9.95845pt,9.95845pt,box,1.00374pt,55_2,2 [395]Box[55]=Checkbox,0,491.57962pt,480.54802pt,9.95845pt,9.95845pt,box,1.00374pt,55_3,3 [396]Variable[55]=55 [397]QObject-Choice=56. qb [398]Answer[56]=a [399]Answer[56]=b [400]Answer[56]=c [401]Box[56]=Checkbox,0,395.5833pt,466.94801pt,9.95845pt,9.95845pt,box,1.00374pt,56_1,1 [402]Box[56]=Checkbox,0,468.32545pt,466.94801pt,9.95845pt,9.95845pt,box,1.00374pt,56_2,2 [403]Box[56]=Checkbox,0,491.57962pt,466.94801pt,9.95845pt,9.95845pt,box,1.00374pt,56_3,3 [404]Variable[56]=56 [405]QObject-Choice=57. qc [406]Answer[57]=a [407]Answer[57]=b [408]Answer[57]=c [409]Box[57]=Checkbox,0,395.5833pt,453.348pt,9.95845pt,9.95845pt,box,1.00374pt,57_1,1 [410]Box[57]=Checkbox,0,468.32545pt,453.348pt,9.95845pt,9.95845pt,box,1.00374pt,57_2,2 [411]Box[57]=Checkbox,0,491.57962pt,453.348pt,9.95845pt,9.95845pt,box,1.00374pt,57_3,3 [412]Variable[57]=57 ] ============================================================ ============================================================ TEST 9: rangearray ============================================================ [10 [413]QObject-Range=58. qa [414]Range-lower[58]=0,lower [415]Box[58]=Checkbox,0,367.54602pt,758.29315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,58_1,1 [416]Box[58]=Checkbox,0,388.45448pt,758.29315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,58_2,2 [417]Box[58]=Checkbox,0,409.36295pt,758.29315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,58_3,3 [418]Box[58]=Checkbox,0,430.27141pt,758.29315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,58_4,4 [419]Box[58]=Checkbox,0,451.17987pt,758.29315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,58_5,5 [420]Range-upper[58]=4,upper [421]Variable[58]=58 [422]QObject-Range=59. qb [423]Range-lower[59]=0,lower [424]Box[59]=Checkbox,0,367.54602pt,744.69315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,59_1,1 [425]Box[59]=Checkbox,0,388.45448pt,744.69315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,59_2,2 [426]Box[59]=Checkbox,0,409.36295pt,744.69315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,59_3,3 [427]Box[59]=Checkbox,0,430.27141pt,744.69315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,59_4,4 [428]Box[59]=Checkbox,0,451.17987pt,744.69315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,59_5,5 [429]Range-upper[59]=4,upper [430]Variable[59]=59 [431]QObject-Range=60. question text [432]Range-lower[60]=0,textlower [433]Box[60]=Checkbox,0,367.54602pt,731.09314pt,9.95845pt,9.95845pt,ellipse,1.00374pt,60_1,1 [434]Box[60]=Checkbox,0,388.45448pt,731.09314pt,9.95845pt,9.95845pt,ellipse,1.00374pt,60_2,2 [435]Box[60]=Checkbox,0,409.36295pt,731.09314pt,9.95845pt,9.95845pt,ellipse,1.00374pt,60_3,3 [436]Box[60]=Checkbox,0,430.27141pt,731.09314pt,9.95845pt,9.95845pt,ellipse,1.00374pt,60_4,4 [437]Box[60]=Checkbox,0,451.17987pt,731.09314pt,9.95845pt,9.95845pt,ellipse,1.00374pt,60_5,5 [438]Range-upper[60]=4,textupper [439]Variable[60]=60 [440]QObject-Range=61. qa [441]Range-lower[61]=0,lower [442]Box[61]=Checkbox,0,301.19415pt,717.49313pt,9.95845pt,9.95845pt,ellipse,1.00374pt,61_1,1 [443]Box[61]=Checkbox,0,322.10262pt,717.49313pt,9.95845pt,9.95845pt,ellipse,1.00374pt,61_2,2 [444]Box[61]=Checkbox,0,343.01108pt,717.49313pt,9.95845pt,9.95845pt,ellipse,1.00374pt,61_3,3 [445]Box[61]=Checkbox,0,363.91954pt,717.49313pt,9.95845pt,9.95845pt,ellipse,1.00374pt,61_4,4 [446]Box[61]=Checkbox,0,384.828pt,717.49313pt,9.95845pt,9.95845pt,ellipse,1.00374pt,61_5,5 [447]Range-upper[61]=4,upper [448]Answer[61]=other [449]Box[61]=Checkbox,0,459.52988pt,717.49313pt,9.95845pt,9.95845pt,ellipse,1.00374pt,61_6,0 [450]Variable[61]=61 [451]QObject-Range=62. qb [452]Range-lower[62]=0,lower [453]Box[62]=Checkbox,0,301.19415pt,703.89313pt,9.95845pt,9.95845pt,ellipse,1.00374pt,62_1,1 [454]Box[62]=Checkbox,0,322.10262pt,703.89313pt,9.95845pt,9.95845pt,ellipse,1.00374pt,62_2,2 [455]Box[62]=Checkbox,0,343.01108pt,703.89313pt,9.95845pt,9.95845pt,ellipse,1.00374pt,62_3,3 [456]Box[62]=Checkbox,0,363.91954pt,703.89313pt,9.95845pt,9.95845pt,ellipse,1.00374pt,62_4,4 [457]Box[62]=Checkbox,0,384.828pt,703.89313pt,9.95845pt,9.95845pt,ellipse,1.00374pt,62_5,5 [458]Range-upper[62]=4,upper [459]Answer[62]=other [460]Box[62]=Checkbox,0,459.52988pt,703.89313pt,9.95845pt,9.95845pt,ellipse,1.00374pt,62_6,0 [461]Variable[62]=62 [462]QObject-Range=63. question text [463]Range-lower[63]=0,textlower [464]Box[63]=Checkbox,0,301.19415pt,690.29312pt,9.95845pt,9.95845pt,ellipse,1.00374pt,63_1,1 [465]Box[63]=Checkbox,0,322.10262pt,690.29312pt,9.95845pt,9.95845pt,ellipse,1.00374pt,63_2,2 [466]Box[63]=Checkbox,0,343.01108pt,690.29312pt,9.95845pt,9.95845pt,ellipse,1.00374pt,63_3,3 [467]Box[63]=Checkbox,0,363.91954pt,690.29312pt,9.95845pt,9.95845pt,ellipse,1.00374pt,63_4,4 [468]Box[63]=Checkbox,0,384.828pt,690.29312pt,9.95845pt,9.95845pt,ellipse,1.00374pt,63_5,5 [469]Range-upper[63]=4,textupper [470]Answer[63]=textother [471]Box[63]=Checkbox,0,459.52988pt,690.29312pt,9.95845pt,9.95845pt,ellipse,1.00374pt,63_6,0 [472]Variable[63]=63 ] ============================================================ ============================================================ TEST 10: rangearray with variable names ============================================================ [11 [473]QObject-Range=64. qa [474]Range-lower[64]=0,lower [475]Box[64]=Checkbox,0,368.57983pt,758.29315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,64_1,1 [476]Box[64]=Checkbox,0,389.4883pt,758.29315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,64_2,2 [477]Box[64]=Checkbox,0,410.39676pt,758.29315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,64_3,3 [478]Box[64]=Checkbox,0,431.30522pt,758.29315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,64_4,4 [479]Box[64]=Checkbox,0,452.21368pt,758.29315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,64_5,5 [480]Range-upper[64]=4,upper [481]Variable[64]=64 [482]QObject-Range=65. qb [483]Range-lower[65]=0,lower [484]Box[65]=Checkbox,0,368.57983pt,744.69315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,qb_1,1 [485]Box[65]=Checkbox,0,389.4883pt,744.69315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,qb_2,2 [486]Box[65]=Checkbox,0,410.39676pt,744.69315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,qb_3,3 [487]Box[65]=Checkbox,0,431.30522pt,744.69315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,qb_4,4 [488]Box[65]=Checkbox,0,452.21368pt,744.69315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,qb_5,5 [489]Range-upper[65]=4,upper [490]Variable[65]=qb [491]QObject-Range=66. qc [492]Range-lower[66]=0,lower [493]Box[66]=Checkbox,0,368.57983pt,731.09314pt,9.95845pt,9.95845pt,ellipse,1.00374pt,66_1,1 [494]Box[66]=Checkbox,0,389.4883pt,731.09314pt,9.95845pt,9.95845pt,ellipse,1.00374pt,66_2,2 [495]Box[66]=Checkbox,0,410.39676pt,731.09314pt,9.95845pt,9.95845pt,ellipse,1.00374pt,66_3,3 [496]Box[66]=Checkbox,0,431.30522pt,731.09314pt,9.95845pt,9.95845pt,ellipse,1.00374pt,66_4,4 [497]Box[66]=Checkbox,0,452.21368pt,731.09314pt,9.95845pt,9.95845pt,ellipse,1.00374pt,66_5,5 [498]Range-upper[66]=4,upper [499]Variable[66]=66 ] ============================================================ ============================================================ TEST 11: rangearray over multiple columns ============================================================ [12 [500]QObject-Range=67. qa [501]Range-lower[67]=0,l [502]Box[67]=Checkbox,0,176.07834pt,758.29315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,67_1,1 [503]Box[67]=Checkbox,0,196.9868pt,758.29315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,67_2,2 [504]Box[67]=Checkbox,0,217.89526pt,758.29315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,67_3,3 [505]Box[67]=Checkbox,0,238.80373pt,758.29315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,67_4,4 [506]Box[67]=Checkbox,0,259.71219pt,758.29315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,67_5,5 [507]Range-upper[67]=4,u [508]Variable[67]=67 [509]QObject-Range=68. qb [510]Range-lower[68]=0,l [511]Box[68]=Checkbox,0,176.07834pt,744.69315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,68_1,1 [512]Box[68]=Checkbox,0,196.9868pt,744.69315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,68_2,2 [513]Box[68]=Checkbox,0,217.89526pt,744.69315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,68_3,3 [514]Box[68]=Checkbox,0,238.80373pt,744.69315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,68_4,4 [515]Box[68]=Checkbox,0,259.71219pt,744.69315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,68_5,5 [516]Range-upper[68]=4,u [517]Variable[68]=68 [518]QObject-Range=69. qc [519]Range-lower[69]=0,l [520]Box[69]=Checkbox,0,390.20612pt,758.29315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,69_1,1 [521]Box[69]=Checkbox,0,411.11458pt,758.29315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,69_2,2 [522]Box[69]=Checkbox,0,432.02304pt,758.29315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,69_3,3 [523]Box[69]=Checkbox,0,452.9315pt,758.29315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,69_4,4 [524]Box[69]=Checkbox,0,473.83997pt,758.29315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,69_5,5 [525]Range-upper[69]=4,u [526]Variable[69]=69 [527]QObject-Range=70. qd [528]Range-lower[70]=0,l [529]Box[70]=Checkbox,0,390.20612pt,744.69315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,70_1,1 [530]Box[70]=Checkbox,0,411.11458pt,744.69315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,70_2,2 [531]Box[70]=Checkbox,0,432.02304pt,744.69315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,70_3,3 [532]Box[70]=Checkbox,0,452.9315pt,744.69315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,70_4,4 [533]Box[70]=Checkbox,0,473.83997pt,744.69315pt,9.95845pt,9.95845pt,ellipse,1.00374pt,70_5,5 [534]Range-upper[70]=4,u [535]Variable[70]=70 ] ============================================================ (layout.aux) sdaps-1.9.8/tex/class/testfiles/layout.xetex.tlg0000644000175000000660000007110313600505201022461 0ustar benjaminlock00000000000000This is a generated file for the l3build validation system. Don't change this file in any respect. ============================================================ TEST 1: Basic choicearray ============================================================ [2 [1]QObject-Choice=1. qa [2]Answer[1]=a [3]Answer[1]=b [4]Answer[1]=c [5]Box[1]=Checkbox,0,448.00644pt,744.69705pt,9.95845pt,9.95845pt,box,1.00374pt,1_1,1 [6]Box[1]=Checkbox,0,469.96487pt,744.69705pt,9.95845pt,9.95845pt,box,1.00374pt,1_2,2 [7]Box[1]=Checkbox,0,491.92331pt,744.69705pt,9.95845pt,9.95845pt,box,1.00374pt,1_3,3 [8]Variable[1]=1 [9]QObject-Choice=2. qb [10]Answer[2]=a [11]Answer[2]=b [12]Answer[2]=c [13]Box[2]=Checkbox,0,448.00644pt,731.09705pt,9.95845pt,9.95845pt,box,1.00374pt,2_1,1 [14]Box[2]=Checkbox,0,469.96487pt,731.09705pt,9.95845pt,9.95845pt,box,1.00374pt,2_2,2 [15]Box[2]=Checkbox,0,491.92331pt,731.09705pt,9.95845pt,9.95845pt,box,1.00374pt,2_3,3 [16]Variable[2]=2 [17]QObject-Choice=3. qc [18]Answer[3]=a [19]Answer[3]=b [20]Answer[3]=c [21]Box[3]=Checkbox,0,448.00644pt,717.49704pt,9.95845pt,9.95845pt,box,1.00374pt,3_1,1 [22]Box[3]=Checkbox,0,469.96487pt,717.49704pt,9.95845pt,9.95845pt,box,1.00374pt,3_2,2 [23]Box[3]=Checkbox,0,491.92331pt,717.49704pt,9.95845pt,9.95845pt,box,1.00374pt,3_3,3 [24]Variable[3]=3 ] ============================================================ ============================================================ TEST 2: Basic singlechoice choicearray ============================================================ [3 [25]QObject-Option=4. qa [26]Answer[4]=a [27]Answer[4]=b [28]Answer[4]=c [29]Box[4]=Checkbox,0,448.00644pt,744.69705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,4_1,1 [30]Box[4]=Checkbox,0,469.96487pt,744.69705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,4_2,2 [31]Box[4]=Checkbox,0,491.92331pt,744.69705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,4_3,3 [32]Variable[4]=4 [33]QObject-Option=5. qb [34]Answer[5]=a [35]Answer[5]=b [36]Answer[5]=c [37]Box[5]=Checkbox,0,448.00644pt,731.09705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,5_1,1 [38]Box[5]=Checkbox,0,469.96487pt,731.09705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,5_2,2 [39]Box[5]=Checkbox,0,491.92331pt,731.09705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,5_3,3 [40]Variable[5]=5 [41]QObject-Option=6. qc [42]Answer[6]=a [43]Answer[6]=b [44]Answer[6]=c [45]Box[6]=Checkbox,0,448.00644pt,717.49704pt,9.95845pt,9.95845pt,ellipse,1.00374pt,6_1,1 [46]Box[6]=Checkbox,0,469.96487pt,717.49704pt,9.95845pt,9.95845pt,ellipse,1.00374pt,6_2,2 [47]Box[6]=Checkbox,0,491.92331pt,717.49704pt,9.95845pt,9.95845pt,ellipse,1.00374pt,6_3,3 [48]Variable[6]=6 ] ============================================================ ============================================================ TEST 3: choicearray range filtering ============================================================ [4 [49]QObject-Choice=7. start-2 [50]Answer[7]=a [51]Answer[7]=b [52]Box[7]=Checkbox,0,448.00644pt,744.69705pt,9.95845pt,9.95845pt,box,1.00374pt,7_1,1 [53]Box[7]=Checkbox,0,469.96487pt,744.69705pt,9.95845pt,9.95845pt,box,1.00374pt,7_2,2 [54]Variable[7]=7 [55]QObject-Choice=8. 2-end [56]Answer[8]=b [57]Answer[8]=c [58]Box[8]=Checkbox,0,469.96487pt,731.09705pt,9.95845pt,9.95845pt,box,1.00374pt,8_2,2 [59]Box[8]=Checkbox,0,491.92331pt,731.09705pt,9.95845pt,9.95845pt,box,1.00374pt,8_3,3 [60]Variable[8]=8 [61]QObject-Choice=9. 1-2 [62]Answer[9]=a [63]Answer[9]=b [64]Box[9]=Checkbox,0,448.00644pt,717.49704pt,9.95845pt,9.95845pt,box,1.00374pt,9_1,1 [65]Box[9]=Checkbox,0,469.96487pt,717.49704pt,9.95845pt,9.95845pt,box,1.00374pt,9_2,2 [66]Variable[9]=9 [67]QObject-Choice=10. 1 and 3 [68]Answer[10]=a [69]Answer[10]=c [70]Box[10]=Checkbox,0,448.00644pt,703.89703pt,9.95845pt,9.95845pt,box,1.00374pt,10_1,1 [71]Box[10]=Checkbox,0,491.92331pt,703.89703pt,9.95845pt,9.95845pt,box,1.00374pt,10_3,3 [72]Variable[10]=10 [73]QObject-Choice=11. range to 1 and 3 [74]Answer[11]=a [75]Answer[11]=c [76]Box[11]=Checkbox,0,448.00644pt,690.29703pt,9.95845pt,9.95845pt,box,1.00374pt,11_1,1 [77]Box[11]=Checkbox,0,491.92331pt,690.29703pt,9.95845pt,9.95845pt,box,1.00374pt,11_3,3 [78]Variable[11]=11 [79]QObject-Choice=12. 1 and 2 plus end [80]Answer[12]=a [81]Answer[12]=b [82]Answer[12]=c [83]Box[12]=Checkbox,0,448.00644pt,676.69702pt,9.95845pt,9.95845pt,box,1.00374pt,12_1,1 [84]Box[12]=Checkbox,0,469.96487pt,676.69702pt,9.95845pt,9.95845pt,box,1.00374pt,12_2,2 [85]Box[12]=Checkbox,0,491.92331pt,676.69702pt,9.95845pt,9.95845pt,box,1.00374pt,12_3,3 [86]Variable[12]=12 [87]QObject-Choice=13. start-2 [88]Answer[13]=a [89]Answer[13]=b [90]Box[13]=Checkbox,0,448.00644pt,649.49701pt,9.95845pt,9.95845pt,box,1.00374pt,13_a,1 [91]Box[13]=Checkbox,0,469.96487pt,649.49701pt,9.95845pt,9.95845pt,box,1.00374pt,13_b,2 [92]Variable[13]=13 [93]QObject-Choice=14. 2-end [94]Answer[14]=b [95]Answer[14]=c [96]Box[14]=Checkbox,0,469.96487pt,635.897pt,9.95845pt,9.95845pt,box,1.00374pt,14_b,2 [97]Box[14]=Checkbox,0,491.92331pt,635.897pt,9.95845pt,9.95845pt,box,1.00374pt,14_c,3 [98]Variable[14]=14 [99]QObject-Choice=15. 1-2 [100]Answer[15]=a [101]Answer[15]=b [102]Box[15]=Checkbox,0,448.00644pt,622.297pt,9.95845pt,9.95845pt,box,1.00374pt,15_a,1 [103]Box[15]=Checkbox,0,469.96487pt,622.297pt,9.95845pt,9.95845pt,box,1.00374pt,15_b,2 [104]Variable[15]=15 [105]QObject-Choice=16. 1 and 3 [106]Answer[16]=a [107]Answer[16]=c [108]Box[16]=Checkbox,0,448.00644pt,608.69699pt,9.95845pt,9.95845pt,box,1.00374pt,16_a,1 [109]Box[16]=Checkbox,0,491.92331pt,608.69699pt,9.95845pt,9.95845pt,box,1.00374pt,16_c,3 [110]Variable[16]=16 [111]QObject-Choice=17. range to 1 and 3 [112]Answer[17]=a [113]Answer[17]=c [114]Box[17]=Checkbox,0,448.00644pt,595.09698pt,9.95845pt,9.95845pt,box,1.00374pt,17_a,1 [115]Box[17]=Checkbox,0,491.92331pt,595.09698pt,9.95845pt,9.95845pt,box,1.00374pt,17_c,3 [116]Variable[17]=17 [117]QObject-Choice=18. 1 and 2 plus end [118]Answer[18]=a [119]Answer[18]=b [120]Answer[18]=c [121]Box[18]=Checkbox,0,448.00644pt,581.49698pt,9.95845pt,9.95845pt,box,1.00374pt,18_a,1 [122]Box[18]=Checkbox,0,469.96487pt,581.49698pt,9.95845pt,9.95845pt,box,1.00374pt,18_b,2 [123]Box[18]=Checkbox,0,491.92331pt,581.49698pt,9.95845pt,9.95845pt,box,1.00374pt,18_c,3 [124]Variable[18]=18 ] ============================================================ ============================================================ TEST 4: choicearray range filtering for singlechoice ============================================================ [5 [125]QObject-Option=19. start-2 [126]Answer[19]=a [127]Answer[19]=b [128]Box[19]=Checkbox,0,448.00644pt,744.69705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,19_1,1 [129]Box[19]=Checkbox,0,469.96487pt,744.69705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,19_2,2 [130]Variable[19]=19 [131]QObject-Option=20. 2-end [132]Answer[20]=b [133]Answer[20]=c [134]Box[20]=Checkbox,0,469.96487pt,731.09705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,20_2,2 [135]Box[20]=Checkbox,0,491.92331pt,731.09705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,20_3,3 [136]Variable[20]=20 [137]QObject-Option=21. 1-2 [138]Answer[21]=a [139]Answer[21]=b [140]Box[21]=Checkbox,0,448.00644pt,717.49704pt,9.95845pt,9.95845pt,ellipse,1.00374pt,21_1,1 [141]Box[21]=Checkbox,0,469.96487pt,717.49704pt,9.95845pt,9.95845pt,ellipse,1.00374pt,21_2,2 [142]Variable[21]=21 [143]QObject-Option=22. 1 and 3 [144]Answer[22]=a [145]Answer[22]=c [146]Box[22]=Checkbox,0,448.00644pt,703.89703pt,9.95845pt,9.95845pt,ellipse,1.00374pt,22_1,1 [147]Box[22]=Checkbox,0,491.92331pt,703.89703pt,9.95845pt,9.95845pt,ellipse,1.00374pt,22_3,3 [148]Variable[22]=22 [149]QObject-Option=23. range to 1 and 3 [150]Answer[23]=a [151]Answer[23]=c [152]Box[23]=Checkbox,0,448.00644pt,690.29703pt,9.95845pt,9.95845pt,ellipse,1.00374pt,23_1,1 [153]Box[23]=Checkbox,0,491.92331pt,690.29703pt,9.95845pt,9.95845pt,ellipse,1.00374pt,23_3,3 [154]Variable[23]=23 [155]QObject-Option=24. 1 and 2 plus end [156]Answer[24]=a [157]Answer[24]=b [158]Answer[24]=c [159]Box[24]=Checkbox,0,448.00644pt,676.69702pt,9.95845pt,9.95845pt,ellipse,1.00374pt,24_1,1 [160]Box[24]=Checkbox,0,469.96487pt,676.69702pt,9.95845pt,9.95845pt,ellipse,1.00374pt,24_2,2 [161]Box[24]=Checkbox,0,491.92331pt,676.69702pt,9.95845pt,9.95845pt,ellipse,1.00374pt,24_3,3 [162]Variable[24]=24 [163]QObject-Option=25. start-2 [164]Answer[25]=a [165]Answer[25]=b [166]Box[25]=Checkbox,0,448.00644pt,649.49701pt,9.95845pt,9.95845pt,ellipse,1.00374pt,25_1,11 [167]Box[25]=Checkbox,0,469.96487pt,649.49701pt,9.95845pt,9.95845pt,ellipse,1.00374pt,25_2,12 [168]Variable[25]=25 [169]QObject-Option=26. 2-end [170]Answer[26]=b [171]Answer[26]=c [172]Box[26]=Checkbox,0,469.96487pt,635.897pt,9.95845pt,9.95845pt,ellipse,1.00374pt,26_2,12 [173]Box[26]=Checkbox,0,491.92331pt,635.897pt,9.95845pt,9.95845pt,ellipse,1.00374pt,26_3,13 [174]Variable[26]=26 [175]QObject-Option=27. 1-2 [176]Answer[27]=a [177]Answer[27]=b [178]Box[27]=Checkbox,0,448.00644pt,622.297pt,9.95845pt,9.95845pt,ellipse,1.00374pt,27_1,11 [179]Box[27]=Checkbox,0,469.96487pt,622.297pt,9.95845pt,9.95845pt,ellipse,1.00374pt,27_2,12 [180]Variable[27]=27 [181]QObject-Option=28. 1 and 3 [182]Answer[28]=a [183]Answer[28]=c [184]Box[28]=Checkbox,0,448.00644pt,608.69699pt,9.95845pt,9.95845pt,ellipse,1.00374pt,28_1,11 [185]Box[28]=Checkbox,0,491.92331pt,608.69699pt,9.95845pt,9.95845pt,ellipse,1.00374pt,28_3,13 [186]Variable[28]=28 [187]QObject-Option=29. range to 1 and 3 [188]Answer[29]=a [189]Answer[29]=c [190]Box[29]=Checkbox,0,448.00644pt,595.09698pt,9.95845pt,9.95845pt,ellipse,1.00374pt,29_1,11 [191]Box[29]=Checkbox,0,491.92331pt,595.09698pt,9.95845pt,9.95845pt,ellipse,1.00374pt,29_3,13 [192]Variable[29]=29 [193]QObject-Option=30. 1 and 2 plus end [194]Answer[30]=a [195]Answer[30]=b [196]Answer[30]=c [197]Box[30]=Checkbox,0,448.00644pt,581.49698pt,9.95845pt,9.95845pt,ellipse,1.00374pt,30_1,11 [198]Box[30]=Checkbox,0,469.96487pt,581.49698pt,9.95845pt,9.95845pt,ellipse,1.00374pt,30_2,12 [199]Box[30]=Checkbox,0,491.92331pt,581.49698pt,9.95845pt,9.95845pt,ellipse,1.00374pt,30_3,13 [200]Variable[30]=30 ] ============================================================ ============================================================ TEST 5: choicearray with fragile content ============================================================ [6 [201]QObject-Choice=31. qa [202]Answer[31]=verbatim [203]Answer[31]=b [204]Answer[31]=c [205]Box[31]=Checkbox,0,429.99066pt,744.69705pt,9.95845pt,9.95845pt,box,1.00374pt,31_1,1 [206]Box[31]=Checkbox,0,469.96487pt,744.69705pt,9.95845pt,9.95845pt,box,1.00374pt,31_2,2 [207]Box[31]=Checkbox,0,491.92331pt,744.69705pt,9.95845pt,9.95845pt,box,1.00374pt,31_3,3 [208]Variable[31]=31 [209]QObject-Choice=32. qb [210]Answer[32]=verbatim [211]Answer[32]=b [212]Answer[32]=c [213]Box[32]=Checkbox,0,429.99066pt,731.09705pt,9.95845pt,9.95845pt,box,1.00374pt,32_1,1 [214]Box[32]=Checkbox,0,469.96487pt,731.09705pt,9.95845pt,9.95845pt,box,1.00374pt,32_2,2 [215]Box[32]=Checkbox,0,491.92331pt,731.09705pt,9.95845pt,9.95845pt,box,1.00374pt,32_3,3 [216]Variable[32]=32 [217]QObject-Choice=33. qc [218]Answer[33]=verbatim [219]Answer[33]=b [220]Answer[33]=c [221]Box[33]=Checkbox,0,429.99066pt,717.49704pt,9.95845pt,9.95845pt,box,1.00374pt,33_1,1 [222]Box[33]=Checkbox,0,469.96487pt,717.49704pt,9.95845pt,9.95845pt,box,1.00374pt,33_2,2 [223]Box[33]=Checkbox,0,491.92331pt,717.49704pt,9.95845pt,9.95845pt,box,1.00374pt,33_3,3 [224]Variable[33]=33 ] ============================================================ ============================================================ TEST 6: choicearray with variables in different places ============================================================ [7 [225]QObject-Choice=34. qa [226]Answer[34]=a [227]Answer[34]=b [228]Answer[34]=c [229]Box[34]=Checkbox,0,448.00644pt,744.69705pt,9.95845pt,9.95845pt,box,1.00374pt,34_1,1 [230]Box[34]=Checkbox,0,469.96487pt,744.69705pt,9.95845pt,9.95845pt,box,1.00374pt,34_ab,2 [231]Box[34]=Checkbox,0,491.92331pt,744.69705pt,9.95845pt,9.95845pt,box,1.00374pt,34_3,3 [232]Variable[34]=34 [233]QObject-Choice=35. qb [234]Answer[35]=a [235]Answer[35]=b [236]Answer[35]=c [237]Box[35]=Checkbox,0,448.00644pt,731.09705pt,9.95845pt,9.95845pt,box,1.00374pt,qb_1,1 [238]Box[35]=Checkbox,0,469.96487pt,731.09705pt,9.95845pt,9.95845pt,box,1.00374pt,qb_ab,2 [239]Box[35]=Checkbox,0,491.92331pt,731.09705pt,9.95845pt,9.95845pt,box,1.00374pt,qb_3,3 [240]Variable[35]=qb [241]QObject-Choice=36. qc [242]Answer[36]=a [243]Answer[36]=b [244]Answer[36]=c [245]Box[36]=Checkbox,0,448.00644pt,717.49704pt,9.95845pt,9.95845pt,box,1.00374pt,36_1,1 [246]Box[36]=Checkbox,0,469.96487pt,717.49704pt,9.95845pt,9.95845pt,box,1.00374pt,36_ab,2 [247]Box[36]=Checkbox,0,491.92331pt,717.49704pt,9.95845pt,9.95845pt,box,1.00374pt,36_3,3 [248]Variable[36]=36 ] ============================================================ ============================================================ TEST 7: vertical choicearray ============================================================ [8 [249]QObject-Choice=37. qa [250]Answer[37]=verbatim [251]Answer[37]=b [252]Answer[37]=c [257]QObject-Choice=38. qb only 2 [258]Answer[38]=b [261]QObject-Choice=39. qc [262]Answer[39]=verbatim [263]Answer[39]=b [264]Answer[39]=c [253]Box[37]=Checkbox,0,411.48398pt,744.69705pt,9.95845pt,9.95845pt,box,1.00374pt,37_1,1 [265]Box[39]=Checkbox,0,491.58083pt,744.69705pt,9.95845pt,9.95845pt,box,1.00374pt,39_1,1 [254]Box[37]=Checkbox,0,411.48398pt,731.09705pt,9.95845pt,9.95845pt,box,1.00374pt,37_2,2 [259]Box[38]=Checkbox,0,451.74593pt,731.09705pt,9.95845pt,9.95845pt,box,1.00374pt,38_2,2 [266]Box[39]=Checkbox,0,491.58083pt,731.09705pt,9.95845pt,9.95845pt,box,1.00374pt,39_2,2 [255]Box[37]=Checkbox,0,411.48398pt,717.49704pt,9.95845pt,9.95845pt,box,1.00374pt,37_3,3 [256]Variable[37]=37 [260]Variable[38]=38 [267]Box[39]=Checkbox,0,491.58083pt,717.49704pt,9.95845pt,9.95845pt,box,1.00374pt,39_3,3 [268]Variable[39]=39 ] ============================================================ ============================================================ TEST 8: choicearray alignment ============================================================ [9 [269]QObject-Choice=40. qa [270]Answer[40]=long string [271]Answer[40]=b [272]Answer[40]=c [273]Box[40]=Checkbox,0,427.38457pt,744.69705pt,9.95845pt,9.95845pt,box,1.00374pt,40_1,1 [274]Box[40]=Checkbox,0,469.96487pt,744.69705pt,9.95845pt,9.95845pt,box,1.00374pt,40_2,2 [275]Box[40]=Checkbox,0,491.92331pt,744.69705pt,9.95845pt,9.95845pt,box,1.00374pt,40_3,3 [276]Variable[40]=40 [277]QObject-Choice=41. qb [278]Answer[41]=long string [279]Answer[41]=b [280]Answer[41]=c [281]Box[41]=Checkbox,0,427.38457pt,731.09705pt,9.95845pt,9.95845pt,box,1.00374pt,41_1,1 [282]Box[41]=Checkbox,0,469.96487pt,731.09705pt,9.95845pt,9.95845pt,box,1.00374pt,41_2,2 [283]Box[41]=Checkbox,0,491.92331pt,731.09705pt,9.95845pt,9.95845pt,box,1.00374pt,41_3,3 [284]Variable[41]=41 [285]QObject-Choice=42. qc [286]Answer[42]=long string [287]Answer[42]=b [288]Answer[42]=c [289]Box[42]=Checkbox,0,427.38457pt,717.49704pt,9.95845pt,9.95845pt,box,1.00374pt,42_1,1 [290]Box[42]=Checkbox,0,469.96487pt,717.49704pt,9.95845pt,9.95845pt,box,1.00374pt,42_2,2 [291]Box[42]=Checkbox,0,491.92331pt,717.49704pt,9.95845pt,9.95845pt,box,1.00374pt,42_3,3 [292]Variable[42]=42 [293]QObject-Choice=43. qa [294]Answer[43]=a [295]Answer[43]=b [296]Answer[43]=c [297]Box[43]=Checkbox,0,427.38457pt,690.29703pt,9.95845pt,9.95845pt,box,1.00374pt,43_1,1 [298]Box[43]=Checkbox,0,469.96487pt,690.29703pt,9.95845pt,9.95845pt,box,1.00374pt,43_2,2 [299]Box[43]=Checkbox,0,491.92331pt,690.29703pt,9.95845pt,9.95845pt,box,1.00374pt,43_3,3 [300]Variable[43]=43 [301]QObject-Choice=44. qb [302]Answer[44]=a [303]Answer[44]=b [304]Answer[44]=c [305]Box[44]=Checkbox,0,427.38457pt,676.69702pt,9.95845pt,9.95845pt,box,1.00374pt,44_1,1 [306]Box[44]=Checkbox,0,469.96487pt,676.69702pt,9.95845pt,9.95845pt,box,1.00374pt,44_2,2 [307]Box[44]=Checkbox,0,491.92331pt,676.69702pt,9.95845pt,9.95845pt,box,1.00374pt,44_3,3 [308]Variable[44]=44 [309]QObject-Choice=45. qc [310]Answer[45]=a [311]Answer[45]=b [312]Answer[45]=c [313]Box[45]=Checkbox,0,427.38457pt,663.09702pt,9.95845pt,9.95845pt,box,1.00374pt,45_1,1 [314]Box[45]=Checkbox,0,469.96487pt,663.09702pt,9.95845pt,9.95845pt,box,1.00374pt,45_2,2 [315]Box[45]=Checkbox,0,491.92331pt,663.09702pt,9.95845pt,9.95845pt,box,1.00374pt,45_3,3 [316]Variable[45]=45 [317]QObject-Choice=46. qa [318]Answer[46]=a [319]Answer[46]=b [320]Answer[46]=c [325]QObject-Choice=47. qb [326]Answer[47]=a [327]Answer[47]=b [328]Answer[47]=c [333]QObject-Choice=48. qc [334]Answer[48]=a [335]Answer[48]=b [336]Answer[48]=c [321]Box[46]=Checkbox,0,403.17842pt,639.37343pt,9.95845pt,9.95845pt,box,1.00374pt,46_1,1 [329]Box[47]=Checkbox,0,468.32423pt,639.37343pt,9.95845pt,9.95845pt,box,1.00374pt,47_1,1 [337]Box[48]=Checkbox,0,491.58083pt,639.37343pt,9.95845pt,9.95845pt,box,1.00374pt,48_1,1 [322]Box[46]=Checkbox,0,403.17842pt,625.77342pt,9.95845pt,9.95845pt,box,1.00374pt,46_2,2 [330]Box[47]=Checkbox,0,468.32423pt,625.77342pt,9.95845pt,9.95845pt,box,1.00374pt,47_2,2 [338]Box[48]=Checkbox,0,491.58083pt,625.77342pt,9.95845pt,9.95845pt,box,1.00374pt,48_2,2 [323]Box[46]=Checkbox,0,403.17842pt,612.17342pt,9.95845pt,9.95845pt,box,1.00374pt,46_3,3 [324]Variable[46]=46 [331]Box[47]=Checkbox,0,468.32423pt,612.17342pt,9.95845pt,9.95845pt,box,1.00374pt,47_3,3 [332]Variable[47]=47 [339]Box[48]=Checkbox,0,491.58083pt,612.17342pt,9.95845pt,9.95845pt,box,1.00374pt,48_3,3 [340]Variable[48]=48 [341]QObject-Choice=49. different long string [342]Answer[49]=a [343]Answer[49]=b [344]Answer[49]=c [349]QObject-Choice=50. qb [350]Answer[50]=a [351]Answer[50]=b [352]Answer[50]=c [357]QObject-Choice=51. qc [358]Answer[51]=a [359]Answer[51]=b [360]Answer[51]=c [345]Box[49]=Checkbox,0,403.17842pt,584.9734pt,9.95845pt,9.95845pt,box,1.00374pt,49_1,1 [353]Box[50]=Checkbox,0,468.32423pt,584.9734pt,9.95845pt,9.95845pt,box,1.00374pt,50_1,1 [361]Box[51]=Checkbox,0,491.58083pt,584.9734pt,9.95845pt,9.95845pt,box,1.00374pt,51_1,1 [346]Box[49]=Checkbox,0,403.17842pt,571.3734pt,9.95845pt,9.95845pt,box,1.00374pt,49_2,2 [354]Box[50]=Checkbox,0,468.32423pt,571.3734pt,9.95845pt,9.95845pt,box,1.00374pt,50_2,2 [362]Box[51]=Checkbox,0,491.58083pt,571.3734pt,9.95845pt,9.95845pt,box,1.00374pt,51_2,2 [347]Box[49]=Checkbox,0,403.17842pt,557.77339pt,9.95845pt,9.95845pt,box,1.00374pt,49_3,3 [348]Variable[49]=49 [355]Box[50]=Checkbox,0,468.32423pt,557.77339pt,9.95845pt,9.95845pt,box,1.00374pt,50_3,3 [356]Variable[50]=50 [363]Box[51]=Checkbox,0,491.58083pt,557.77339pt,9.95845pt,9.95845pt,box,1.00374pt,51_3,3 [364]Variable[51]=51 [365]QObject-Choice=52. yet another long string [366]Answer[52]=a [367]Answer[52]=b [368]Answer[52]=c [373]QObject-Choice=53. qb [374]Answer[53]=a [375]Answer[53]=b [376]Answer[53]=c [381]QObject-Choice=54. qc [382]Answer[54]=a [383]Answer[54]=b [384]Answer[54]=c [369]Box[52]=Checkbox,0,395.57365pt,534.97044pt,9.95845pt,9.95845pt,box,1.00374pt,52_1,1 [377]Box[53]=Checkbox,0,468.32423pt,534.97044pt,9.95845pt,9.95845pt,box,1.00374pt,53_1,1 [385]Box[54]=Checkbox,0,491.58083pt,534.97044pt,9.95845pt,9.95845pt,box,1.00374pt,54_1,1 [370]Box[52]=Checkbox,0,395.57365pt,521.37044pt,9.95845pt,9.95845pt,box,1.00374pt,52_2,2 [378]Box[53]=Checkbox,0,468.32423pt,521.37044pt,9.95845pt,9.95845pt,box,1.00374pt,53_2,2 [386]Box[54]=Checkbox,0,491.58083pt,521.37044pt,9.95845pt,9.95845pt,box,1.00374pt,54_2,2 [371]Box[52]=Checkbox,0,395.57365pt,507.77043pt,9.95845pt,9.95845pt,box,1.00374pt,52_3,3 [372]Variable[52]=52 [379]Box[53]=Checkbox,0,468.32423pt,507.77043pt,9.95845pt,9.95845pt,box,1.00374pt,53_3,3 [380]Variable[53]=53 [387]Box[54]=Checkbox,0,491.58083pt,507.77043pt,9.95845pt,9.95845pt,box,1.00374pt,54_3,3 [388]Variable[54]=54 [389]QObject-Choice=55. yet another long string [390]Answer[55]=a [391]Answer[55]=b [392]Answer[55]=c [393]Box[55]=Checkbox,0,395.57365pt,480.57042pt,9.95845pt,9.95845pt,box,1.00374pt,55_1,1 [394]Box[55]=Checkbox,0,468.32423pt,480.57042pt,9.95845pt,9.95845pt,box,1.00374pt,55_2,2 [395]Box[55]=Checkbox,0,491.58083pt,480.57042pt,9.95845pt,9.95845pt,box,1.00374pt,55_3,3 [396]Variable[55]=55 [397]QObject-Choice=56. qb [398]Answer[56]=a [399]Answer[56]=b [400]Answer[56]=c [401]Box[56]=Checkbox,0,395.57365pt,466.97041pt,9.95845pt,9.95845pt,box,1.00374pt,56_1,1 [402]Box[56]=Checkbox,0,468.32423pt,466.97041pt,9.95845pt,9.95845pt,box,1.00374pt,56_2,2 [403]Box[56]=Checkbox,0,491.58083pt,466.97041pt,9.95845pt,9.95845pt,box,1.00374pt,56_3,3 [404]Variable[56]=56 [405]QObject-Choice=57. qc [406]Answer[57]=a [407]Answer[57]=b [408]Answer[57]=c [409]Box[57]=Checkbox,0,395.57365pt,453.3704pt,9.95845pt,9.95845pt,box,1.00374pt,57_1,1 [410]Box[57]=Checkbox,0,468.32423pt,453.3704pt,9.95845pt,9.95845pt,box,1.00374pt,57_2,2 [411]Box[57]=Checkbox,0,491.58083pt,453.3704pt,9.95845pt,9.95845pt,box,1.00374pt,57_3,3 [412]Variable[57]=57 ] ============================================================ ============================================================ TEST 9: rangearray ============================================================ [10 [413]QObject-Range=58. qa [414]Range-lower[58]=0,lower [415]Box[58]=Checkbox,0,367.54584pt,758.29706pt,9.95845pt,9.95845pt,ellipse,1.00374pt,58_1,1 [416]Box[58]=Checkbox,0,388.45427pt,758.29706pt,9.95845pt,9.95845pt,ellipse,1.00374pt,58_2,2 [417]Box[58]=Checkbox,0,409.3627pt,758.29706pt,9.95845pt,9.95845pt,ellipse,1.00374pt,58_3,3 [418]Box[58]=Checkbox,0,430.27113pt,758.29706pt,9.95845pt,9.95845pt,ellipse,1.00374pt,58_4,4 [419]Box[58]=Checkbox,0,451.17957pt,758.29706pt,9.95845pt,9.95845pt,ellipse,1.00374pt,58_5,5 [420]Range-upper[58]=4,upper [421]Variable[58]=58 [422]QObject-Range=59. qb [423]Range-lower[59]=0,lower [424]Box[59]=Checkbox,0,367.54584pt,744.69705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,59_1,1 [425]Box[59]=Checkbox,0,388.45427pt,744.69705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,59_2,2 [426]Box[59]=Checkbox,0,409.3627pt,744.69705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,59_3,3 [427]Box[59]=Checkbox,0,430.27113pt,744.69705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,59_4,4 [428]Box[59]=Checkbox,0,451.17957pt,744.69705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,59_5,5 [429]Range-upper[59]=4,upper [430]Variable[59]=59 [431]QObject-Range=60. question text [432]Range-lower[60]=0,textlower [433]Box[60]=Checkbox,0,367.54584pt,731.09705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,60_1,1 [434]Box[60]=Checkbox,0,388.45427pt,731.09705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,60_2,2 [435]Box[60]=Checkbox,0,409.3627pt,731.09705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,60_3,3 [436]Box[60]=Checkbox,0,430.27113pt,731.09705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,60_4,4 [437]Box[60]=Checkbox,0,451.17957pt,731.09705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,60_5,5 [438]Range-upper[60]=4,textupper [439]Variable[60]=60 [440]QObject-Range=61. qa [441]Range-lower[61]=0,lower [442]Box[61]=Checkbox,0,301.19731pt,717.49704pt,9.95845pt,9.95845pt,ellipse,1.00374pt,61_1,1 [443]Box[61]=Checkbox,0,322.10574pt,717.49704pt,9.95845pt,9.95845pt,ellipse,1.00374pt,61_2,2 [444]Box[61]=Checkbox,0,343.01418pt,717.49704pt,9.95845pt,9.95845pt,ellipse,1.00374pt,61_3,3 [445]Box[61]=Checkbox,0,363.9226pt,717.49704pt,9.95845pt,9.95845pt,ellipse,1.00374pt,61_4,4 [446]Box[61]=Checkbox,0,384.83104pt,717.49704pt,9.95845pt,9.95845pt,ellipse,1.00374pt,61_5,5 [447]Range-upper[61]=4,upper [448]Answer[61]=other [449]Box[61]=Checkbox,0,459.53322pt,717.49704pt,9.95845pt,9.95845pt,ellipse,1.00374pt,61_6,0 [450]Variable[61]=61 [451]QObject-Range=62. qb [452]Range-lower[62]=0,lower [453]Box[62]=Checkbox,0,301.19731pt,703.89703pt,9.95845pt,9.95845pt,ellipse,1.00374pt,62_1,1 [454]Box[62]=Checkbox,0,322.10574pt,703.89703pt,9.95845pt,9.95845pt,ellipse,1.00374pt,62_2,2 [455]Box[62]=Checkbox,0,343.01418pt,703.89703pt,9.95845pt,9.95845pt,ellipse,1.00374pt,62_3,3 [456]Box[62]=Checkbox,0,363.9226pt,703.89703pt,9.95845pt,9.95845pt,ellipse,1.00374pt,62_4,4 [457]Box[62]=Checkbox,0,384.83104pt,703.89703pt,9.95845pt,9.95845pt,ellipse,1.00374pt,62_5,5 [458]Range-upper[62]=4,upper [459]Answer[62]=other [460]Box[62]=Checkbox,0,459.53322pt,703.89703pt,9.95845pt,9.95845pt,ellipse,1.00374pt,62_6,0 [461]Variable[62]=62 [462]QObject-Range=63. question text [463]Range-lower[63]=0,textlower [464]Box[63]=Checkbox,0,301.19731pt,690.29703pt,9.95845pt,9.95845pt,ellipse,1.00374pt,63_1,1 [465]Box[63]=Checkbox,0,322.10574pt,690.29703pt,9.95845pt,9.95845pt,ellipse,1.00374pt,63_2,2 [466]Box[63]=Checkbox,0,343.01418pt,690.29703pt,9.95845pt,9.95845pt,ellipse,1.00374pt,63_3,3 [467]Box[63]=Checkbox,0,363.9226pt,690.29703pt,9.95845pt,9.95845pt,ellipse,1.00374pt,63_4,4 [468]Box[63]=Checkbox,0,384.83104pt,690.29703pt,9.95845pt,9.95845pt,ellipse,1.00374pt,63_5,5 [469]Range-upper[63]=4,textupper [470]Answer[63]=textother [471]Box[63]=Checkbox,0,459.53322pt,690.29703pt,9.95845pt,9.95845pt,ellipse,1.00374pt,63_6,0 [472]Variable[63]=63 ] ============================================================ ============================================================ TEST 10: rangearray with variable names ============================================================ [11 [473]QObject-Range=64. qa [474]Range-lower[64]=0,lower [475]Box[64]=Checkbox,0,368.5642pt,758.29706pt,9.95845pt,9.95845pt,ellipse,1.00374pt,64_1,1 [476]Box[64]=Checkbox,0,389.47263pt,758.29706pt,9.95845pt,9.95845pt,ellipse,1.00374pt,64_2,2 [477]Box[64]=Checkbox,0,410.38106pt,758.29706pt,9.95845pt,9.95845pt,ellipse,1.00374pt,64_3,3 [478]Box[64]=Checkbox,0,431.28949pt,758.29706pt,9.95845pt,9.95845pt,ellipse,1.00374pt,64_4,4 [479]Box[64]=Checkbox,0,452.19792pt,758.29706pt,9.95845pt,9.95845pt,ellipse,1.00374pt,64_5,5 [480]Range-upper[64]=4,upper [481]Variable[64]=64 [482]QObject-Range=65. qb [483]Range-lower[65]=0,lower [484]Box[65]=Checkbox,0,368.5642pt,744.69705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,qb_1,1 [485]Box[65]=Checkbox,0,389.47263pt,744.69705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,qb_2,2 [486]Box[65]=Checkbox,0,410.38106pt,744.69705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,qb_3,3 [487]Box[65]=Checkbox,0,431.28949pt,744.69705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,qb_4,4 [488]Box[65]=Checkbox,0,452.19792pt,744.69705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,qb_5,5 [489]Range-upper[65]=4,upper [490]Variable[65]=qb [491]QObject-Range=66. qc [492]Range-lower[66]=0,lower [493]Box[66]=Checkbox,0,368.5642pt,731.09705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,66_1,1 [494]Box[66]=Checkbox,0,389.47263pt,731.09705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,66_2,2 [495]Box[66]=Checkbox,0,410.38106pt,731.09705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,66_3,3 [496]Box[66]=Checkbox,0,431.28949pt,731.09705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,66_4,4 [497]Box[66]=Checkbox,0,452.19792pt,731.09705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,66_5,5 [498]Range-upper[66]=4,upper [499]Variable[66]=66 ] ============================================================ ============================================================ TEST 11: rangearray over multiple columns ============================================================ [12 [500]QObject-Range=67. qa [501]Range-lower[67]=0,l [502]Box[67]=Checkbox,0,176.07361pt,758.29706pt,9.95845pt,9.95845pt,ellipse,1.00374pt,67_1,1 [503]Box[67]=Checkbox,0,196.98204pt,758.29706pt,9.95845pt,9.95845pt,ellipse,1.00374pt,67_2,2 [504]Box[67]=Checkbox,0,217.89047pt,758.29706pt,9.95845pt,9.95845pt,ellipse,1.00374pt,67_3,3 [505]Box[67]=Checkbox,0,238.7989pt,758.29706pt,9.95845pt,9.95845pt,ellipse,1.00374pt,67_4,4 [506]Box[67]=Checkbox,0,259.70734pt,758.29706pt,9.95845pt,9.95845pt,ellipse,1.00374pt,67_5,5 [507]Range-upper[67]=4,u [508]Variable[67]=67 [509]QObject-Range=68. qb [510]Range-lower[68]=0,l [511]Box[68]=Checkbox,0,176.07361pt,744.69705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,68_1,1 [512]Box[68]=Checkbox,0,196.98204pt,744.69705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,68_2,2 [513]Box[68]=Checkbox,0,217.89047pt,744.69705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,68_3,3 [514]Box[68]=Checkbox,0,238.7989pt,744.69705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,68_4,4 [515]Box[68]=Checkbox,0,259.70734pt,744.69705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,68_5,5 [516]Range-upper[68]=4,u [517]Variable[68]=68 [518]QObject-Range=69. qc [519]Range-lower[69]=0,l [520]Box[69]=Checkbox,0,390.20139pt,758.29706pt,9.95845pt,9.95845pt,ellipse,1.00374pt,69_1,1 [521]Box[69]=Checkbox,0,411.10982pt,758.29706pt,9.95845pt,9.95845pt,ellipse,1.00374pt,69_2,2 [522]Box[69]=Checkbox,0,432.01825pt,758.29706pt,9.95845pt,9.95845pt,ellipse,1.00374pt,69_3,3 [523]Box[69]=Checkbox,0,452.92668pt,758.29706pt,9.95845pt,9.95845pt,ellipse,1.00374pt,69_4,4 [524]Box[69]=Checkbox,0,473.83511pt,758.29706pt,9.95845pt,9.95845pt,ellipse,1.00374pt,69_5,5 [525]Range-upper[69]=4,u [526]Variable[69]=69 [527]QObject-Range=70. qd [528]Range-lower[70]=0,l [529]Box[70]=Checkbox,0,390.20139pt,744.69705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,70_1,1 [530]Box[70]=Checkbox,0,411.10982pt,744.69705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,70_2,2 [531]Box[70]=Checkbox,0,432.01825pt,744.69705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,70_3,3 [532]Box[70]=Checkbox,0,452.92668pt,744.69705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,70_4,4 [533]Box[70]=Checkbox,0,473.83511pt,744.69705pt,9.95845pt,9.95845pt,ellipse,1.00374pt,70_5,5 [534]Range-upper[70]=4,u [535]Variable[70]=70 ] ============================================================ (layout.aux) sdaps-1.9.8/tex/class/testfiles/pdftest.lvt0000644000175000000660000000332013153476713021516 0ustar benjaminlock00000000000000\documentclass{minimal} \input{regression-test} \OMIT \usepackage{sdapsbase} \usepackage{sdapspdf} \def\logpos#1{\lognamedpos{#1}#1} \def\lognamedpos#1{\pdfsavepos\write128{POSITION #1: \the\pdflastxpos,\the\pdflastypos}} \newenvironment{MYTEST}[1]{% \begingroup% \global\advance \gTESTint 1 % \SEPARATOR% \LONGTYPEOUT{% TEST \the\gTESTint: \detokenize{#1}}% \SEPARATOR% }{% \SEPARATOR% \LONGTYPEOUT{}% \endgroup% } \newenvironment{OMITPAGE}{% \begingroup% \OMIT% }{% \vfil\break% \TIMO% \endgroup% } \newenvironment{MYTESTPAGE}[1]{% \begin{MYTEST}{#1}% }{% \vfil\break% \end{MYTEST}% } \newenvironment{MYTESTPAGESHOW}[1]{% \begin{MYTESTPAGE}{#1}% \showoutput% }{% \end{MYTESTPAGE}% } \TIMO \begin{document} \START \begin{OMITPAGE} % Some font stuff $ a + b $ \textbackslash \end{OMITPAGE} \OMIT \begin{Form} \TIMO \begin{MYTESTPAGESHOW}{PDF Forms} \ExplSyntaxOn % Set the pdf_form option for all boxes (*) \sdaps_context_append:nn{*}{pdf_form=true} % Or for checkboxes and textboxes separately %\sdaps_context_append:nn{checkbox}{pdf_form=true} %\sdaps_context_append:nn{textbox}{pdf_form=true} \noindent \sdaps_checkbox:nn {} {} {}~ \sdaps_context_set:n{checkbox={checkboxsymbol=5}} \sdaps_checkbox:nn {} {} {}~ \sdaps_context_set:n{checkbox={default=true}} \sdaps_checkbox:nn {} {} {}~ \sdaps_context_set:n{checkbox={default=true,checkboxsymbol=5}} \sdaps_checkbox:nn {} {} {} \sdaps_textbox_vhstretch:nnn { text } { 4cm } { 0 } \ExplSyntaxOff \end{MYTESTPAGESHOW} \end{Form} \OMIT \end{document} \TIMO sdaps-1.9.8/tex/class/testfiles/pdftest.tlg0000644000175000000660000003352713600505201021471 0ustar benjaminlock00000000000000This is a generated file for the l3build validation system. Don't change this file in any respect. ============================================================ TEST 1: PDF Forms ============================================================ Completed box being shipped out [2] \vbox(578.15999+0.0)x469.75499 .\hbox(0.0+0.0)x0.0 .\vbox(0.0+0.0)x0.0, glue set 1.00374fil ..\kern 0.0 ..\kern 0.0 ..\kern -1.00374 ..\hbox(0.0+0.0)x0.0, glue set 1.00374fil ...\kern 0.0 ...\kern 0.0 ...\kern -1.00374 ...\pdfdest name{page.2} xyz ...\penalty 10000 ...\glue 0.0 plus 1.0fil minus 1.0fil ..\glue 0.0 plus 1.0fil minus 1.0fil .\glue(\lineskip) 0.0 .\vbox(578.15999+0.0)x469.75499 ..\glue 0.0 ..\vbox(578.15999+0.0)x469.75499 ...\vbox(0.0+0.0)x469.75499 ....\glue 0.0 plus 1.0fil ....\hbox(0.0+0.0)x469.75499 .....\pdfcolorstack 0 push {0 g 0 G} .....\hbox(0.0+0.0)x469.75499 .....\pdfcolorstack 0 pop ...\glue 0.0 ...\glue(\lineskip) 0.0 ...\vbox(578.15999+0.0)x469.75499, glue set 449.66837fil ....\pdfrefobj{<>} ....\pdfrefobj{<>/AP<< /N <>\ETC.} ................\vbox(9.95845+0.0)x9.95845, glue set 9.95845fill .................\hbox(0.0+0.0)x9.95845, glue set 9.95845fill ..................\glue 0.0 plus 1.0fill .................\glue 0.0 plus 1.0fill ................\pdfendlink ................\write1{\string \HyField@AuxAddToFields {25}} ...............\glue 0.0 .............\pdfliteral{Q } .............\glue 0.0 ............\glue 0.0 plus 1.0fil minus 1.0fil ...........\pdfliteral{Q } ...........\glue 0.0 ...........\glue 0.0 ...........\pdfliteral{Q } .........\glue 0.0 .........\glue 0.0 .........\pdfliteral{Q } .........\glue 0.0 .........\pdfliteral{Q } .........\glue 0.0 plus 1.0fil minus 1.0fil ........\pdfliteral{n } ........\pdfliteral{Q } ........\glue 0.0 plus 1.0fil minus 1.0fil .....\glue 3.33333 plus 1.66666 minus 1.11111 .....\hbox(8.42366+1.53477)x9.95844 ......\pdfsavepos ......\hbox(9.95844+0.0)x9.95844, shifted 1.53477 .......\glue 0.0 .......\hbox(0.0+0.0)x0.0 ........\pdfliteral{q } ........\pdfliteral{0 G } ........\pdfliteral{0 g } ........\pdfliteral{0.3985 w } ........\hbox(0.0+0.0)x0.0 .........\pdfliteral{q } .........\glue 0.0 .........\pdfliteral{q } .........\pdfliteral{1.0 w } .........\pdfliteral{1 g } .........\pdfliteral{0 G } .........\pdfliteral{0.49998 0.49998 m } .........\pdfliteral{0.49998 0.49998 m } .........\pdfliteral{0.49998 9.42136 l } .........\pdfliteral{9.42136 9.42136 l } .........\pdfliteral{9.42136 0.49998 l } .........\pdfliteral{h } .........\pdfliteral{9.42136 9.42136 m } .........\pdfliteral{B } .........\glue 0.0 .........\pdfliteral{Q } .........\pdfliteral{q } .........\glue 0.0 .........\hbox(0.0+0.0)x0.0 ..........\hbox(0.0+0.0)x0.0 ...........\pdfliteral{q } ...........\glue 0.0 ...........\glue 0.0 ...........\glue 0.0 ...........\glue 0.0 ...........\glue 0.0 ...........\pdfliteral{q } ...........\hbox(0.0+0.0)x0.0 ............\glue 0.0 ............\hbox(0.0+0.0)x0.0, shifted -0.00002 .............\pdfliteral{1.0 0.0 0.0 1.0 0.0 0.0 cm } .............\pdfliteral{q } .............\hbox(0.0+0.0)x0.0 ..............\hbox(9.95845+0.0)x9.95845 ...............\pdfliteral{0 G } ...............\pdfliteral{0 g } ...............\hbox(9.95845+0.0)x9.95845 ................\pdfstartlink(*+*)x* action user{/Subtype/Widget/F 4/T(1)/FT/Btn/Q 0/BS<>/AP<< /N <>\ETC.} ................\vbox(9.95845+0.0)x9.95845, glue set 9.95845fill .................\hbox(0.0+0.0)x9.95845, glue set 9.95845fill ..................\glue 0.0 plus 1.0fill .................\glue 0.0 plus 1.0fill ................\pdfendlink ................\write1{\string \HyField@AuxAddToFields {26}} ...............\glue 0.0 .............\pdfliteral{Q } .............\glue 0.0 ............\glue 0.0 plus 1.0fil minus 1.0fil ...........\pdfliteral{Q } ...........\glue 0.0 ...........\glue 0.0 ...........\pdfliteral{Q } .........\glue 0.0 .........\glue 0.0 .........\pdfliteral{Q } .........\glue 0.0 .........\pdfliteral{Q } .........\glue 0.0 plus 1.0fil minus 1.0fil ........\pdfliteral{n } ........\pdfliteral{Q } ........\glue 0.0 plus 1.0fil minus 1.0fil .....\glue 3.33333 plus 1.66666 minus 1.11111 .....\hbox(8.42366+1.53477)x9.95844 ......\pdfsavepos ......\hbox(9.95844+0.0)x9.95844, shifted 1.53477 .......\glue 0.0 .......\hbox(0.0+0.0)x0.0 ........\pdfliteral{q } ........\pdfliteral{0 G } ........\pdfliteral{0 g } ........\pdfliteral{0.3985 w } ........\hbox(0.0+0.0)x0.0 .........\pdfliteral{q } .........\glue 0.0 .........\pdfliteral{q } .........\pdfliteral{1.0 w } .........\pdfliteral{1 g } .........\pdfliteral{0 G } .........\pdfliteral{0.49998 0.49998 m } .........\pdfliteral{0.49998 0.49998 m } .........\pdfliteral{0.49998 9.42136 l } .........\pdfliteral{9.42136 9.42136 l } .........\pdfliteral{9.42136 0.49998 l } .........\pdfliteral{h } .........\pdfliteral{9.42136 9.42136 m } .........\pdfliteral{B } .........\glue 0.0 .........\pdfliteral{Q } .........\pdfliteral{q } .........\glue 0.0 .........\hbox(0.0+0.0)x0.0 ..........\hbox(0.0+0.0)x0.0 ...........\pdfliteral{q } ...........\glue 0.0 ...........\glue 0.0 ...........\glue 0.0 ...........\glue 0.0 ...........\glue 0.0 ...........\pdfliteral{q } ...........\hbox(0.0+0.0)x0.0 ............\glue 0.0 ............\hbox(0.0+0.0)x0.0, shifted -0.00002 .............\pdfliteral{1.0 0.0 0.0 1.0 0.0 0.0 cm } .............\pdfliteral{q } .............\hbox(0.0+0.0)x0.0 ..............\hbox(9.95845+0.0)x9.95845 ...............\pdfliteral{0 G } ...............\pdfliteral{0 g } ...............\hbox(9.95845+0.0)x9.95845 ................\pdfstartlink(*+*)x* action user{/Subtype/Widget/F 4/T(1)/FT/Btn/Q 0/BS<>/AP<< /N <>\ETC.} ................\vbox(9.95845+0.0)x9.95845, glue set 9.95845fill .................\hbox(0.0+0.0)x9.95845, glue set 9.95845fill ..................\glue 0.0 plus 1.0fill .................\glue 0.0 plus 1.0fill ................\pdfendlink ................\write1{\string \HyField@AuxAddToFields {27}} ...............\glue 0.0 .............\pdfliteral{Q } .............\glue 0.0 ............\glue 0.0 plus 1.0fil minus 1.0fil ...........\pdfliteral{Q } ...........\glue 0.0 ...........\glue 0.0 ...........\pdfliteral{Q } .........\glue 0.0 .........\glue 0.0 .........\pdfliteral{Q } .........\glue 0.0 .........\pdfliteral{Q } .........\glue 0.0 plus 1.0fil minus 1.0fil ........\pdfliteral{n } ........\pdfliteral{Q } ........\glue 0.0 plus 1.0fil minus 1.0fil .....\glue 3.33333 plus 1.66666 minus 1.11111 .....\hbox(8.42366+1.53477)x9.95844 ......\pdfsavepos ......\hbox(9.95844+0.0)x9.95844, shifted 1.53477 .......\glue 0.0 .......\hbox(0.0+0.0)x0.0 ........\pdfliteral{q } ........\pdfliteral{0 G } ........\pdfliteral{0 g } ........\pdfliteral{0.3985 w } ........\hbox(0.0+0.0)x0.0 .........\pdfliteral{q } .........\glue 0.0 .........\pdfliteral{q } .........\pdfliteral{1.0 w } .........\pdfliteral{1 g } .........\pdfliteral{0 G } .........\pdfliteral{0.49998 0.49998 m } .........\pdfliteral{0.49998 0.49998 m } .........\pdfliteral{0.49998 9.42136 l } .........\pdfliteral{9.42136 9.42136 l } .........\pdfliteral{9.42136 0.49998 l } .........\pdfliteral{h } .........\pdfliteral{9.42136 9.42136 m } .........\pdfliteral{B } .........\glue 0.0 .........\pdfliteral{Q } .........\pdfliteral{q } .........\glue 0.0 .........\hbox(0.0+0.0)x0.0 ..........\hbox(0.0+0.0)x0.0 ...........\pdfliteral{q } ...........\glue 0.0 ...........\glue 0.0 ...........\glue 0.0 ...........\glue 0.0 ...........\glue 0.0 ...........\pdfliteral{q } ...........\hbox(0.0+0.0)x0.0 ............\glue 0.0 ............\hbox(0.0+0.0)x0.0, shifted -0.00002 .............\pdfliteral{1.0 0.0 0.0 1.0 0.0 0.0 cm } .............\pdfliteral{q } .............\hbox(0.0+0.0)x0.0 ..............\hbox(9.95845+0.0)x9.95845 ...............\pdfliteral{0 G } ...............\pdfliteral{0 g } ...............\hbox(9.95845+0.0)x9.95845 ................\pdfstartlink(*+*)x* action user{/Subtype/Widget/F 4/T(1)/FT/Btn/Q 0/BS<>/AP<< /N <>\ETC.} ................\vbox(9.95845+0.0)x9.95845, glue set 9.95845fill .................\hbox(0.0+0.0)x9.95845, glue set 9.95845fill ..................\glue 0.0 plus 1.0fill .................\glue 0.0 plus 1.0fill ................\pdfendlink ................\write1{\string \HyField@AuxAddToFields {28}} ...............\glue 0.0 .............\pdfliteral{Q } .............\glue 0.0 ............\glue 0.0 plus 1.0fil minus 1.0fil ...........\pdfliteral{Q } ...........\glue 0.0 ...........\glue 0.0 ...........\pdfliteral{Q } .........\glue 0.0 .........\glue 0.0 .........\pdfliteral{Q } .........\glue 0.0 .........\pdfliteral{Q } .........\glue 0.0 plus 1.0fil minus 1.0fil ........\pdfliteral{n } ........\pdfliteral{Q } ........\glue 0.0 plus 1.0fil minus 1.0fil .....\penalty 10000 .....\glue(\parfillskip) 0.0 plus 1.0fil .....\glue(\rightskip) 0.0 ....\penalty 150 ....\glue(\baselineskip) 3.14583 ....\vbox(7.3194+0.0)x469.75499 .....\hbox(7.3194+0.0)x469.75499, glue set 469.75499fill ......\rule(7.3194+0.0)x0.0 ......\pdfsavepos ......\write1{\noexpand \pgfsyspdfmark {textboxtop0}{\the \pdflastxpos }{\the \pdflastypos \ETC.} ......\penalty 10000 ......\glue(\parfillskip) 0.0 plus 1.0fil ......\glue(\rightskip) 0.0 plus 1.0fill ....\penalty 10000 ....\cleaders 106.49162 .....\hbox(0.0+0.0)x0.0 ....\penalty 10000 ....\cleaders 0.0 .....\hbox(0.0+0.0)x0.0 ....\penalty 10000 ....\vbox(0.0+0.0)x469.75499 .....\hbox(0.0+0.0)x469.75499, glue set 469.75499fill ......\glue(\leftskip) 0.0 plus 1.0fill ......\hbox(0.0+0.0)x0.0 .......\glue 0.0 .......\hbox(0.0+0.0)x0.0 ........\pdfliteral{q } ........\pdfliteral{0 G } ........\pdfliteral{0 g } ........\pdfliteral{0.3985 w } ........\hbox(0.0+0.0)x0.0 .........\pdfliteral{q } .........\glue 0.0 .........\pdfliteral{q } .........\pdfliteral{1.0 w } .........\pdfliteral{1 g } .........\pdfliteral{0 G } .........\pdfliteral{-467.50603 112.88728 m } .........\pdfliteral{-467.50603 112.88728 m } .........\pdfliteral{-467.50603 0.5 l } .........\pdfliteral{-0.5 0.5 l } .........\pdfliteral{-0.5 112.88728 l } .........\pdfliteral{h } .........\pdfliteral{-0.5 0.5 m } .........\pdfliteral{B } .........\glue 0.0 .........\pdfliteral{Q } .........\pdfliteral{q } .........\glue 0.0 .........\hbox(0.0+0.0)x0.0 ..........\hbox(0.0+0.0)x0.0 ...........\pdfliteral{q } ...........\glue 0.0 ...........\glue 0.0 ...........\glue 0.0 ...........\glue 0.0 ...........\glue 0.0 ...........\pdfliteral{q } ...........\hbox(0.0+0.0)x0.0 ............\glue -467.75499 ............\hbox(0.0+0.0)x0.0, shifted -2.00002 .............\pdfliteral{1.0 0.0 0.0 1.0 0.0 0.0 cm } .............\pdfliteral{q } .............\hbox(0.0+0.0)x0.0 ..............\hbox(109.81102+0.0)x465.75499 ...............\pdfliteral{0 G } ...............\pdfliteral{0 g } ...............\hbox(109.81102+0.0)x465.75499 ................\pdfstartlink(*+*)x* action user{/Subtype/Widget/F 4/T(text)/FT/Tx/Ff 4096/Q 0/BS<>/DA(/He\ETC.} ................\vbox(109.81102+0.0)x465.75499, glue set 109.81102fill .................\hbox(0.0+0.0)x465.75499, glue set 465.75499fill ..................\glue 0.0 plus 1.0fill .................\glue 0.0 plus 1.0fill ................\pdfendlink ................\write1{\string \HyField@AuxAddToFields {29}} ...............\glue 0.0 .............\pdfliteral{Q } .............\glue 0.0 ............\glue 0.0 plus 1.0fil minus 1.0fil ...........\pdfliteral{Q } ...........\glue 0.0 ...........\glue 0.0 ...........\pdfliteral{Q } .........\glue 0.0 .........\glue 0.0 .........\pdfliteral{Q } .........\glue 0.0 .........\pdfliteral{Q } .........\hbox(0.0+0.0)x0.0 ..........\pdfsavepos ..........\write1{\noexpand \pgfsyspdfmark {pgfid5}{\the \pdflastxpos }{\the \pdflastypos \ETC.} .........\glue 0.0 plus 1.0fil minus 1.0fil ........\pdfliteral{n } ........\pdfliteral{Q } ........\glue 0.0 plus 1.0fil minus 1.0fil ......\penalty 10000 ......\glue(\parfillskip) 0.0 plus 1.0fil ......\glue(\rightskip) 0.0 ....\penalty 10000 ....\glue -2.15277 ....\penalty 10000 ....\hbox(0.0+2.15277)x0.0 .....\rule(0.0+2.15277)x0.0 ....\glue 0.0 plus 1.0fil ....\glue 0.0 ...\glue(\baselineskip) 0.0 ...\hbox(0.0+0.0)x469.75499 ....\pdfcolorstack 0 push {0 g 0 G} ....\hbox(0.0+0.0)x469.75499 ....\pdfcolorstack 0 pop ============================================================ sdaps-1.9.8/tex/class/testfiles/pdftest.xetex.tlg0000644000175000000660000004043513600505201022621 0ustar benjaminlock00000000000000This is a generated file for the l3build validation system. Don't change this file in any respect. ============================================================ TEST 1: PDF Forms ============================================================ Completed box being shipped out [2] \vbox(578.15999+0.0)x469.75499 .\hbox(0.0+0.0)x0.0 ..\special{pdf:put @resources << /ColorSpace @pgfcolorspaces >>} .\vbox(0.0+0.0)x0.0, glue set 1.00374fil ..\kern 0.0 ..\kern 0.0 ..\kern -1.00374 ..\hbox(0.0+0.0)x0.0, glue set 1.00374fil ...\kern 0.0 ...\kern 0.0 ...\kern -1.00374 ...\special{pdf:dest (page.2) [@thispage /XYZ @xpos @ypos null]} ...\penalty 10000 ...\glue 0.0 plus 1.0fil minus 1.0fil ..\glue 0.0 plus 1.0fil minus 1.0fil .\glue(\lineskip) 0.0 .\vbox(578.15999+0.0)x469.75499 ..\glue 0.0 ..\vbox(578.15999+0.0)x469.75499 ...\vbox(0.0+0.0)x469.75499 ....\glue 0.0 plus 1.0fil ....\hbox(0.0+0.0)x469.75499 .....\special{color push gray 0} .....\hbox(0.0+0.0)x469.75499 .....\special{color pop} ...\glue 0.0 ...\glue(\lineskip) 0.0 ...\vbox(578.15999+0.0)x469.75499, glue set 449.67595fil ....\special{pdf:obj @OBJpdfdocencoding<>} ....\glue(\topskip) 1.57278 ....\hbox(8.42722+1.53122)x469.75499, glue set 419.93124fil .....\hbox(8.42722+1.53122)x9.95844 ......\pdfsavepos ......\hbox(9.95844+0.0)x9.95844, shifted 1.53122 .......\glue 0.0 .......\hbox(0.0+0.0)x0.0 ........\special{pdf:bcontent} ........\special{pdf:code q } ........\special{pdf:code 0 G } ........\special{pdf:code 0 g } ........\special{pdf:code 0.3985 w } ........\hbox(0.0+0.0)x0.0 .........\special{pdf:code q } .........\glue 0.0 .........\special{pdf:code q } .........\special{pdf:code 1.0 w } .........\special{pdf:code 1 g } .........\special{pdf:code 0 G } .........\special{pdf:code 0.49998 0.49998 m } .........\special{pdf:code 0.49998 0.49998 m } .........\special{pdf:code 0.49998 9.42136 l } .........\special{pdf:code 9.42136 9.42136 l } .........\special{pdf:code 9.42136 0.49998 l } .........\special{pdf:code h } .........\special{pdf:code 9.42136 9.42136 m } .........\special{pdf:code B } .........\glue 0.0 .........\special{pdf:code Q } .........\special{pdf:code q } .........\glue 0.0 .........\hbox(0.0+0.0)x0.0 ..........\hbox(0.0+0.0)x0.0 ...........\special{pdf:code q } ...........\glue 0.0 ...........\glue 0.0 ...........\glue 0.0 ...........\glue 0.0 ...........\glue 0.0 ...........\special{pdf:code q } ...........\special{pdf:code q -1 0 0 -1 0 0 cm q} ...........\special{pdf: econtent} ...........\special{pdf: bcontent} ...........\special{pdf:code -1 0 0 -1 0 0 cm} ...........\special{pdf:code q} ...........\special{pdf: econtent} ...........\special{pdf:code 0 J [] 0 d} ...........\special{pdf:bcolor [1]} ...........\special{pdf:bcolor [0]} ...........\special{pdf:btrans matrix 1.0 0.0 0.0 1.0 0.0 0.0} ...........\hbox(0.0+0.0)x0.0 ............\hbox(9.95845+0.0)x9.95845 .............\special{pdf:code 0 G } .............\special{pdf:code 0 g } .............\hbox(9.95845+0.0)x9.95845 ..............\special{pdf:ann @check1 height 9.95845pt width 9.95845pt depth 0.0pt <, 2011, 2012, 2013. # msgid "" msgstr "" "Project-Id-Version: SDAPS 0.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:09+0100\n" "PO-Revision-Date: 2019-01-09 14:27+0000\n" "Last-Translator: JinaJita \n" "Language-Team: German \n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 3.4-dev\n" "X-Poedit-Language: German\n" "X-Poedit-Country: GERMANY\n" "X-Poedit-SourceCharset: utf-8\n" #. The language name of the LaTeX dictionary file for translator #: ../tex_translations.in.h:2 msgid "English" msgstr "German" #. Used as an overlay for questionnaires that are not yet done #: ../tex_translations.in.h:4 msgid "draft" msgstr "Entwurf" #. Label for the survey-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:6 msgid "Survey-ID:" msgstr "Umfrage-ID:" #. Label for the questionnaire-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:8 msgid "Questionnaire-ID:" msgstr "Fragebogen-ID:" #. Default instructions on the questionnaire #: ../tex_translations.in.h:10 msgid "" "This questionnaire is evaluated automatically. Please use a pen to fill in " "your answers as follows:" msgstr "" "Der Fragebogen wird maschinell erfasst. Bitte mit Kugelschreiber wie folgt " "ausfüllen:" #. Instruction on the questionnaire: Next to checked textbox #: ../tex_translations.in.h:12 msgid "Selected" msgstr "Ausgewählt" #. Instruction on the questionnaire: Next to filled checkbox #: ../tex_translations.in.h:14 msgid "Fill to select" msgstr "Ausfüllen zum auswählen" #. Instruction on the questionnaire: Next to filled and checked checkbox #: ../tex_translations.in.h:16 msgid "Undo select" msgstr "Auswahl zurücknehmen" #. Instruction on the questionnaire: Multiple choice question #: ../tex_translations.in.h:18 msgid "Multiple-choice (select all applicable options)" msgstr "Mehrfachauswahl (alle zutreffenden Optionen auswählen)" #. Instruction on the questionnaire: Single choice question #: ../tex_translations.in.h:20 msgid "Single-choice (select only one option)" msgstr "Einzelauswahl (nur eine Option auswählen)" #. LaTeX based report: Label for the number of people that answered #: ../tex_translations.in.h:22 msgid "Answers" msgstr "Antworten" #. LaTeX based report: The calculated mean value #: ../tex_translations.in.h:24 msgid "Mean" msgstr "Durchschnitt" #. LaTeX based report: The standard deviation #: ../tex_translations.in.h:26 msgid "Standard-Deviation" msgstr "Standardabweichung" #~ msgid "Check" #~ msgstr "Ankreuzen" #~ msgid "Uncheck to correct" #~ msgstr "Korrigieren" #~ msgid "You can check any number of boxes in selection questions." #~ msgstr "Bei Auswahlfeldern dürfen mehrere Antworten angekreuzt werden." #~ msgid "" #~ "For questions with a range (1--\\arabic{markcheckboxcount}) mark the " #~ "answer that fits best." #~ msgstr "" #~ "Bei Bewertungsfragen (Skala 1--\\arabic{markcheckboxcount}) darf nur ein " #~ "Kästchen angekreuzt werden." sdaps-1.9.8/tex/po/es.po0000644000175000000660000000615513410742231015570 0ustar benjaminlock00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: SDAPS 0.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:09+0100\n" "PO-Revision-Date: 2014-09-19 15:15+0200\n" "Last-Translator: Benjamin Berg \n" "Language-Team: Spanish \n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 1.10-dev\n" #. The language name of the LaTeX dictionary file for translator #: ../tex_translations.in.h:2 msgid "English" msgstr "Spanish" #. Used as an overlay for questionnaires that are not yet done #: ../tex_translations.in.h:4 msgid "draft" msgstr "borrador" #. Label for the survey-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:6 msgid "Survey-ID:" msgstr "ID de encuesta:" #. Label for the questionnaire-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:8 msgid "Questionnaire-ID:" msgstr "ID de cuestionario:" #. Default instructions on the questionnaire #: ../tex_translations.in.h:10 #, fuzzy msgid "" "This questionnaire is evaluated automatically. Please use a pen to fill in " "your answers as follows:" msgstr "" "El cuestionario se lee automáticamente por un programa computerizado. Por " "favor, utilice un bolígrafo para completar sus respuestas." #. Instruction on the questionnaire: Next to checked textbox #: ../tex_translations.in.h:12 msgid "Selected" msgstr "" #. Instruction on the questionnaire: Next to filled checkbox #: ../tex_translations.in.h:14 msgid "Fill to select" msgstr "" #. Instruction on the questionnaire: Next to filled and checked checkbox #: ../tex_translations.in.h:16 msgid "Undo select" msgstr "" #. Instruction on the questionnaire: Multiple choice question #: ../tex_translations.in.h:18 msgid "Multiple-choice (select all applicable options)" msgstr "" #. Instruction on the questionnaire: Single choice question #: ../tex_translations.in.h:20 msgid "Single-choice (select only one option)" msgstr "" #. LaTeX based report: Label for the number of people that answered #: ../tex_translations.in.h:22 msgid "Answers" msgstr "Respuestas" #. LaTeX based report: The calculated mean value #: ../tex_translations.in.h:24 msgid "Mean" msgstr "Media" #. LaTeX based report: The standard deviation #: ../tex_translations.in.h:26 msgid "Standard-Deviation" msgstr "Desviación estándar" #~ msgid "Check" #~ msgstr "Marque" #~ msgid "Uncheck to correct" #~ msgstr "Desmarque para corregir" #~ msgid "You can check any number of boxes in selection questions." #~ msgstr "" #~ "Puede marcar varios encasillados en las preguntas de selección multiple." #~ msgid "" #~ "For questions with a range (1--\\arabic{markcheckboxcount}) mark the " #~ "answer that fits best." #~ msgstr "" #~ "Para preguntas con un rango (1--\\arabic{markcheckboxcount}), escoja la " #~ "mejor contestación." sdaps-1.9.8/tex/po/fi.po0000644000175000000660000000616713410742231015562 0ustar benjaminlock00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: SDAPS\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:09+0100\n" "PO-Revision-Date: 2014-08-17 12:53+0200\n" "Last-Translator: Joonas Joensuu \n" "Language-Team: Finnish \n" "Language: fi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 1.10-dev\n" #. The language name of the LaTeX dictionary file for translator #: ../tex_translations.in.h:2 msgid "English" msgstr "Finnish" #. Used as an overlay for questionnaires that are not yet done #: ../tex_translations.in.h:4 msgid "draft" msgstr "luonnos" #. Label for the survey-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:6 msgid "Survey-ID:" msgstr "Kyselyn tunnus:" #. Label for the questionnaire-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:8 msgid "Questionnaire-ID:" msgstr "Kyselylomakkeen tunnus:" #. Default instructions on the questionnaire #: ../tex_translations.in.h:10 #, fuzzy msgid "" "This questionnaire is evaluated automatically. Please use a pen to fill in " "your answers as follows:" msgstr "" "Tämä kyselykaavake luetaan automaattisesti tietokoneohjelman avulla. Käytä " "kuulakärkikynää vastatessasi kysymyksiin." #. Instruction on the questionnaire: Next to checked textbox #: ../tex_translations.in.h:12 msgid "Selected" msgstr "" #. Instruction on the questionnaire: Next to filled checkbox #: ../tex_translations.in.h:14 msgid "Fill to select" msgstr "" #. Instruction on the questionnaire: Next to filled and checked checkbox #: ../tex_translations.in.h:16 msgid "Undo select" msgstr "" #. Instruction on the questionnaire: Multiple choice question #: ../tex_translations.in.h:18 msgid "Multiple-choice (select all applicable options)" msgstr "" #. Instruction on the questionnaire: Single choice question #: ../tex_translations.in.h:20 msgid "Single-choice (select only one option)" msgstr "" #. LaTeX based report: Label for the number of people that answered #: ../tex_translations.in.h:22 msgid "Answers" msgstr "Vastaukset" #. LaTeX based report: The calculated mean value #: ../tex_translations.in.h:24 msgid "Mean" msgstr "Keskiarvo" #. LaTeX based report: The standard deviation #: ../tex_translations.in.h:26 msgid "Standard-Deviation" msgstr "Keskihajonta" #~ msgid "Check" #~ msgstr "Valitse" #~ msgid "Uncheck to correct" #~ msgstr "Poista valinta korjataksesi" #~ msgid "You can check any number of boxes in selection questions." #~ msgstr "Voit valita haluamasi määrän laatikoita valintakysymyksissä." #~ msgid "" #~ "For questions with a range (1--\\arabic{markcheckboxcount}) mark the " #~ "answer that fits best." #~ msgstr "" #~ "Kysymyksissä, jotka vastaus kysytään vaihteluvälillä (1--" #~ "\\arabic{markcheckboxcount}), valitse vastaus, joka sopii parhaiten." sdaps-1.9.8/tex/po/fr.po0000644000175000000660000000636313421045054015572 0ustar benjaminlock00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: SDAPS 0.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:09+0100\n" "PO-Revision-Date: 2019-01-18 03:21+0000\n" "Last-Translator: ButterflyOfFire \n" "Language-Team: French \n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" "X-Generator: Weblate 3.4-dev\n" #. The language name of the LaTeX dictionary file for translator #: ../tex_translations.in.h:2 msgid "English" msgstr "French" #. Used as an overlay for questionnaires that are not yet done #: ../tex_translations.in.h:4 msgid "draft" msgstr "brouillon" #. Label for the survey-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:6 msgid "Survey-ID:" msgstr "ID-Sondage :" #. Label for the questionnaire-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:8 msgid "Questionnaire-ID:" msgstr "ID-Questionnaire :" #. Default instructions on the questionnaire #: ../tex_translations.in.h:10 msgid "" "This questionnaire is evaluated automatically. Please use a pen to fill in " "your answers as follows:" msgstr "" "Ce questionnaire est évalué automatiquement. Veuillez utiliser un stylo pour " "remplir vos réponses comme suit :" #. Instruction on the questionnaire: Next to checked textbox #: ../tex_translations.in.h:12 msgid "Selected" msgstr "Sélectionné" #. Instruction on the questionnaire: Next to filled checkbox #: ../tex_translations.in.h:14 msgid "Fill to select" msgstr "Cocher pour sélectionner" #. Instruction on the questionnaire: Next to filled and checked checkbox #: ../tex_translations.in.h:16 msgid "Undo select" msgstr "Annuler la sélection" #. Instruction on the questionnaire: Multiple choice question #: ../tex_translations.in.h:18 msgid "Multiple-choice (select all applicable options)" msgstr "Choix multiples (sélectionnez toutes les options applicables)" #. Instruction on the questionnaire: Single choice question #: ../tex_translations.in.h:20 msgid "Single-choice (select only one option)" msgstr "À choix unique (ne choisir qu’une seule option)" #. LaTeX based report: Label for the number of people that answered #: ../tex_translations.in.h:22 msgid "Answers" msgstr "Réponses" #. LaTeX based report: The calculated mean value #: ../tex_translations.in.h:24 msgid "Mean" msgstr "Moyenne" #. LaTeX based report: The standard deviation #: ../tex_translations.in.h:26 msgid "Standard-Deviation" msgstr "Écart-type" #~ msgid "Check" #~ msgstr "Cocher" #~ msgid "Uncheck to correct" #~ msgstr "Noircir pour corriger" #~ msgid "You can check any number of boxes in selection questions." #~ msgstr "" #~ "Cochez toutes les réponses voulues dans les questions à choix multiples." #~ msgid "" #~ "For questions with a range (1--\\arabic{markcheckboxcount}) mark the " #~ "answer that fits best." #~ msgstr "" #~ "Ne cochez qu'une seule réponse pour les questions d'échelles (1--" #~ "\\arabic{markcheckboxcount})." sdaps-1.9.8/tex/po/it.po0000644000175000000660000000620713410742231015573 0ustar benjaminlock00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:09+0100\n" "PO-Revision-Date: 2018-01-18 16:20+0000\n" "Last-Translator: Martina Caramenti \n" "Language-Team: Italian \n" "Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 2.19-dev\n" #. The language name of the LaTeX dictionary file for translator #: ../tex_translations.in.h:2 msgid "English" msgstr "Italian" #. Used as an overlay for questionnaires that are not yet done #: ../tex_translations.in.h:4 msgid "draft" msgstr "bozza" #. Label for the survey-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:6 msgid "Survey-ID:" msgstr "ID del sondaggio:" #. Label for the questionnaire-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:8 msgid "Questionnaire-ID:" msgstr "ID del Questionario:" #. Default instructions on the questionnaire #: ../tex_translations.in.h:10 #, fuzzy msgid "" "This questionnaire is evaluated automatically. Please use a pen to fill in " "your answers as follows:" msgstr "" "Questo questionario viene letto automaticamente con supporti elettronici. Si " "prega di compilarlo usando una penna." #. Instruction on the questionnaire: Next to checked textbox #: ../tex_translations.in.h:12 msgid "Selected" msgstr "" #. Instruction on the questionnaire: Next to filled checkbox #: ../tex_translations.in.h:14 msgid "Fill to select" msgstr "" #. Instruction on the questionnaire: Next to filled and checked checkbox #: ../tex_translations.in.h:16 msgid "Undo select" msgstr "" #. Instruction on the questionnaire: Multiple choice question #: ../tex_translations.in.h:18 msgid "Multiple-choice (select all applicable options)" msgstr "" #. Instruction on the questionnaire: Single choice question #: ../tex_translations.in.h:20 msgid "Single-choice (select only one option)" msgstr "" #. LaTeX based report: Label for the number of people that answered #: ../tex_translations.in.h:22 msgid "Answers" msgstr "Risposte" #. LaTeX based report: The calculated mean value #: ../tex_translations.in.h:24 msgid "Mean" msgstr "Media" #. LaTeX based report: The standard deviation #: ../tex_translations.in.h:26 msgid "Standard-Deviation" msgstr "Deviazione Standard" #~ msgid "Check" #~ msgstr "Marcare" #~ msgid "Uncheck to correct" #~ msgstr "Annerire per correggere" #~ msgid "You can check any number of boxes in selection questions." #~ msgstr "" #~ "Nelle domande a scelta multipla possono essere marcate più risposte." #~ msgid "" #~ "For questions with a range (1--\\arabic{markcheckboxcount}) mark the " #~ "answer that fits best." #~ msgstr "" #~ "Nelle domande con scala di valutazione (1--\\arabic{markcheckboxcount}) " #~ "marcare la casella che meglio rappresenta la propria risposta." sdaps-1.9.8/tex/po/ko.po0000644000175000000660000000450013410742231015562 0ustar benjaminlock00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:09+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: ko\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" #. The language name of the LaTeX dictionary file for translator #: ../tex_translations.in.h:2 msgid "English" msgstr "" #. Used as an overlay for questionnaires that are not yet done #: ../tex_translations.in.h:4 msgid "draft" msgstr "" #. Label for the survey-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:6 msgid "Survey-ID:" msgstr "" #. Label for the questionnaire-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:8 msgid "Questionnaire-ID:" msgstr "" #. Default instructions on the questionnaire #: ../tex_translations.in.h:10 msgid "" "This questionnaire is evaluated automatically. Please use a pen to fill in " "your answers as follows:" msgstr "" #. Instruction on the questionnaire: Next to checked textbox #: ../tex_translations.in.h:12 msgid "Selected" msgstr "" #. Instruction on the questionnaire: Next to filled checkbox #: ../tex_translations.in.h:14 msgid "Fill to select" msgstr "" #. Instruction on the questionnaire: Next to filled and checked checkbox #: ../tex_translations.in.h:16 msgid "Undo select" msgstr "" #. Instruction on the questionnaire: Multiple choice question #: ../tex_translations.in.h:18 msgid "Multiple-choice (select all applicable options)" msgstr "" #. Instruction on the questionnaire: Single choice question #: ../tex_translations.in.h:20 msgid "Single-choice (select only one option)" msgstr "" #. LaTeX based report: Label for the number of people that answered #: ../tex_translations.in.h:22 msgid "Answers" msgstr "" #. LaTeX based report: The calculated mean value #: ../tex_translations.in.h:24 msgid "Mean" msgstr "" #. LaTeX based report: The standard deviation #: ../tex_translations.in.h:26 msgid "Standard-Deviation" msgstr "" sdaps-1.9.8/tex/po/nb.po0000644000175000000660000000632013575523632015570 0ustar benjaminlock00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:09+0100\n" "PO-Revision-Date: 2019-01-01 11:10+0000\n" "Last-Translator: Allan Nordhøy \n" "Language-Team: Norwegian Bokmål \n" "Language: nb\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 3.4-dev\n" #. The language name of the LaTeX dictionary file for translator #: ../tex_translations.in.h:2 msgid "English" msgstr "Norsk" #. Used as an overlay for questionnaires that are not yet done #: ../tex_translations.in.h:4 msgid "draft" msgstr "utkast" #. Label for the survey-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:6 msgid "Survey-ID:" msgstr "Spørreundersøkelses-ID:" #. Label for the questionnaire-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:8 msgid "Questionnaire-ID:" msgstr "Spørreskjema-ID:" #. Default instructions on the questionnaire #: ../tex_translations.in.h:10 #, fuzzy msgid "" "This questionnaire is evaluated automatically. Please use a pen to fill in " "your answers as follows:" msgstr "" "Dette spørreskjemaet blir automatisk lest av et dataprogram. Bruk ei penn " "for å fylle inn svarene dine." #. Instruction on the questionnaire: Next to checked textbox #: ../tex_translations.in.h:12 msgid "Selected" msgstr "Valgt" #. Instruction on the questionnaire: Next to filled checkbox #: ../tex_translations.in.h:14 msgid "Fill to select" msgstr "Fyll for å velge" #. Instruction on the questionnaire: Next to filled and checked checkbox #: ../tex_translations.in.h:16 msgid "Undo select" msgstr "Angre utvalg" #. Instruction on the questionnaire: Multiple choice question #: ../tex_translations.in.h:18 msgid "Multiple-choice (select all applicable options)" msgstr "Flervalg (velg alle passende alternativer)" #. Instruction on the questionnaire: Single choice question #: ../tex_translations.in.h:20 msgid "Single-choice (select only one option)" msgstr "Enkeltvalg (velg kun ett alternativ)" #. LaTeX based report: Label for the number of people that answered #: ../tex_translations.in.h:22 msgid "Answers" msgstr "Svar" #. LaTeX based report: The calculated mean value #: ../tex_translations.in.h:24 msgid "Mean" msgstr "Gjennomsnitt" #. LaTeX based report: The standard deviation #: ../tex_translations.in.h:26 msgid "Standard-Deviation" msgstr "Standardavvik" #~ msgid "Check" #~ msgstr "Kryss av" #~ msgid "Uncheck to correct" #~ msgstr "Fjern avkryssning for å korrigere" #~ msgid "You can check any number of boxes in selection questions." #~ msgstr "Du kan krysse av vilkårlig antall bokser i flervalgsspørsmål." #~ msgid "" #~ "For questions with a range (1--\\arabic{markcheckboxcount}) mark the " #~ "answer that fits best." #~ msgstr "" #~ "For spørsmål med rekkevidde (1--\\arabic{markcheckboxcount}) merk det " #~ "svaret som passer best." sdaps-1.9.8/tex/po/nl.po0000644000175000000660000000626313415403517015600 0ustar benjaminlock00000000000000# Benjamin Berg , 2011, 2012, 2013. # Serge Stroobandt , 2013. msgid "" msgstr "" "Project-Id-Version: SDAPS 0.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:09+0100\n" "PO-Revision-Date: 2018-12-27 20:09+0000\n" "Last-Translator: Serge Stroobandt \n" "Language-Team: Dutch \n" "Language: nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 3.4-dev\n" "X-Poedit-SourceCharset: utf-8\n" #. The language name of the LaTeX dictionary file for translator #: ../tex_translations.in.h:2 msgid "English" msgstr "Dutch" #. Used as an overlay for questionnaires that are not yet done #: ../tex_translations.in.h:4 msgid "draft" msgstr "voorontwerp" #. Label for the survey-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:6 msgid "Survey-ID:" msgstr "Onderzoeks-ID:" #. Label for the questionnaire-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:8 msgid "Questionnaire-ID:" msgstr "Vragenlijst-ID:" #. Default instructions on the questionnaire #: ../tex_translations.in.h:10 msgid "" "This questionnaire is evaluated automatically. Please use a pen to fill in " "your answers as follows:" msgstr "" "De vragenlijst wordt elektronisch ingelezen. Gebruik een balpen of dunne " "viltstift om als volgt te antwoorden:" #. Instruction on the questionnaire: Next to checked textbox #: ../tex_translations.in.h:12 msgid "Selected" msgstr "Geselecteerd" #. Instruction on the questionnaire: Next to filled checkbox #: ../tex_translations.in.h:14 msgid "Fill to select" msgstr "Markeer om te selecteren" #. Instruction on the questionnaire: Next to filled and checked checkbox #: ../tex_translations.in.h:16 msgid "Undo select" msgstr "Selectie ongedaan maken" #. Instruction on the questionnaire: Multiple choice question #: ../tex_translations.in.h:18 msgid "Multiple-choice (select all applicable options)" msgstr "Meerkeuze (selecteer alle opties die van toepassing zijn)" #. Instruction on the questionnaire: Single choice question #: ../tex_translations.in.h:20 msgid "Single-choice (select only one option)" msgstr "Enkelvoudige keuze (selecteer enkel één optie)" #. LaTeX based report: Label for the number of people that answered #: ../tex_translations.in.h:22 msgid "Answers" msgstr "Antwoorden" #. LaTeX based report: The calculated mean value #: ../tex_translations.in.h:24 msgid "Mean" msgstr "Mediaan" #. LaTeX based report: The standard deviation #: ../tex_translations.in.h:26 msgid "Standard-Deviation" msgstr "Standaardafwijking" #~ msgid "Check" #~ msgstr "Aankruisen" #~ msgid "Uncheck to correct" #~ msgstr "Corrigeren" #~ msgid "You can check any number of boxes in selection questions." #~ msgstr "Bij meerkeuzevragen mogen meerdere antwoorden worden aangekruist." #~ msgid "" #~ "For questions with a range (1--\\arabic{markcheckboxcount}) mark the " #~ "answer that fits best." #~ msgstr "" #~ "Bij waarderingsvragen met een bereik (1--\\arabic{markcheckboxcount}) mag " #~ "slechts een hokje worden aangekruist." sdaps-1.9.8/tex/po/pl.po0000644000175000000660000000601413410742231015566 0ustar benjaminlock00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: SDAPS 0.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:09+0100\n" "PO-Revision-Date: 2018-04-10 15:00+0200\n" "Last-Translator: Damian Kulig \n" "Language-Team: LANGUAGE \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " "|| n%100>=20) ? 1 : 2);\n" #. The language name of the LaTeX dictionary file for translator #: ../tex_translations.in.h:2 msgid "English" msgstr "Polish" #. Used as an overlay for questionnaires that are not yet done #: ../tex_translations.in.h:4 msgid "draft" msgstr "szkic" #. Label for the survey-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:6 msgid "Survey-ID:" msgstr "" #. Label for the questionnaire-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:8 msgid "Questionnaire-ID:" msgstr "" #. Default instructions on the questionnaire #: ../tex_translations.in.h:10 #, fuzzy msgid "" "This questionnaire is evaluated automatically. Please use a pen to fill in " "your answers as follows:" msgstr "" "Ten kwestianariusz jest sprawdzany automatycznie. Użyj długopisu wpisując " "odpowiedzi." #. Instruction on the questionnaire: Next to checked textbox #: ../tex_translations.in.h:12 msgid "Selected" msgstr "" #. Instruction on the questionnaire: Next to filled checkbox #: ../tex_translations.in.h:14 msgid "Fill to select" msgstr "" #. Instruction on the questionnaire: Next to filled and checked checkbox #: ../tex_translations.in.h:16 msgid "Undo select" msgstr "" #. Instruction on the questionnaire: Multiple choice question #: ../tex_translations.in.h:18 msgid "Multiple-choice (select all applicable options)" msgstr "" #. Instruction on the questionnaire: Single choice question #: ../tex_translations.in.h:20 msgid "Single-choice (select only one option)" msgstr "" #. LaTeX based report: Label for the number of people that answered #: ../tex_translations.in.h:22 msgid "Answers" msgstr "Odpowiedzi" #. LaTeX based report: The calculated mean value #: ../tex_translations.in.h:24 msgid "Mean" msgstr "Znaczenie" #. LaTeX based report: The standard deviation #: ../tex_translations.in.h:26 msgid "Standard-Deviation" msgstr "" #~ msgid "Check" #~ msgstr "Zaznaczenie" #~ msgid "Uncheck to correct" #~ msgstr "Odznaczenie do poprawy" #~ msgid "You can check any number of boxes in selection questions." #~ msgstr "" #~ "Możesz wybrać dowolną ilość odpowiedzi w zaznaczając odpowiednie kwadraty." #~ msgid "" #~ "For questions with a range (1--\\arabic{markcheckboxcount}) mark the " #~ "answer that fits best." #~ msgstr "" #~ "Dla pytań (1--\arabic{markcheckboxcount}) wybierz odpowiedź, która " #~ "najlepiej pasuje." sdaps-1.9.8/tex/po/pt.po0000644000175000000660000000634413462531573015620 0ustar benjaminlock00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: SDAPS 0.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:09+0100\n" "PO-Revision-Date: 2019-04-30 00:49+0000\n" "Last-Translator: Rui Mendes \n" "Language-Team: Portuguese " "\n" "Language: pt\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 3.6.1\n" #. The language name of the LaTeX dictionary file for translator #: ../tex_translations.in.h:2 msgid "English" msgstr "Portuguese" #. Used as an overlay for questionnaires that are not yet done #: ../tex_translations.in.h:4 msgid "draft" msgstr "projeto" #. Label for the survey-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:6 msgid "Survey-ID:" msgstr "ID da Pesquisa:" #. Label for the questionnaire-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:8 msgid "Questionnaire-ID:" msgstr "ID do Questionário:" #. Default instructions on the questionnaire #: ../tex_translations.in.h:10 msgid "" "This questionnaire is evaluated automatically. Please use a pen to fill in " "your answers as follows:" msgstr "" "Este questionário é lido automaticamente por um programa. Por favor utilize " "uma caneta para preenchê-lo conforme o seguinte:" #. Instruction on the questionnaire: Next to checked textbox #: ../tex_translations.in.h:12 msgid "Selected" msgstr "Selecionado" #. Instruction on the questionnaire: Next to filled checkbox #: ../tex_translations.in.h:14 msgid "Fill to select" msgstr "Preencha para selecionar" #. Instruction on the questionnaire: Next to filled and checked checkbox #: ../tex_translations.in.h:16 msgid "Undo select" msgstr "Desfazer seleção" #. Instruction on the questionnaire: Multiple choice question #: ../tex_translations.in.h:18 msgid "Multiple-choice (select all applicable options)" msgstr "Escolha múltipla (selecione todas as opções aplicáveis)" #. Instruction on the questionnaire: Single choice question #: ../tex_translations.in.h:20 msgid "Single-choice (select only one option)" msgstr "Escolha única (selecione apenas uma opção)" #. LaTeX based report: Label for the number of people that answered #: ../tex_translations.in.h:22 msgid "Answers" msgstr "Respostas" #. LaTeX based report: The calculated mean value #: ../tex_translations.in.h:24 msgid "Mean" msgstr "Média" #. LaTeX based report: The standard deviation #: ../tex_translations.in.h:26 msgid "Standard-Deviation" msgstr "Desvio Padrão" #~ msgid "Check" #~ msgstr "Marcar" #~ msgid "Uncheck to correct" #~ msgstr "Corrigir" #~ msgid "You can check any number of boxes in selection questions." #~ msgstr "Você pode marcar qualquer número de caixas em questões de seleção." #~ msgid "" #~ "For questions with a range (1--\\arabic{markcheckboxcount}) mark the " #~ "answer that fits best." #~ msgstr "" #~ "Em questões com um intervalo (1 - \\arabic{markcheckboxcount}) escolha a " #~ "resposta que se encaixa melhor." sdaps-1.9.8/tex/po/pt_BR.po0000644000175000000660000000613013410742231016160 0ustar benjaminlock00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: SDAPS 0.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:09+0100\n" "PO-Revision-Date: 2014-09-19 15:15+0200\n" "Last-Translator: Benjamin Berg \n" "Language-Team: Portuguese (Brazil) \n" "Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 1.10-dev\n" #. The language name of the LaTeX dictionary file for translator #: ../tex_translations.in.h:2 msgid "English" msgstr "Brazilian" #. Used as an overlay for questionnaires that are not yet done #: ../tex_translations.in.h:4 msgid "draft" msgstr "projeto" #. Label for the survey-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:6 msgid "Survey-ID:" msgstr "ID da Pesquisa:" #. Label for the questionnaire-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:8 msgid "Questionnaire-ID:" msgstr "ID do Questionário:" #. Default instructions on the questionnaire #: ../tex_translations.in.h:10 #, fuzzy msgid "" "This questionnaire is evaluated automatically. Please use a pen to fill in " "your answers as follows:" msgstr "" "Este questionário é lido automaticamente por um programa. Por favor, utilize " "uma caneta para preenchê-lo." #. Instruction on the questionnaire: Next to checked textbox #: ../tex_translations.in.h:12 msgid "Selected" msgstr "" #. Instruction on the questionnaire: Next to filled checkbox #: ../tex_translations.in.h:14 msgid "Fill to select" msgstr "" #. Instruction on the questionnaire: Next to filled and checked checkbox #: ../tex_translations.in.h:16 msgid "Undo select" msgstr "" #. Instruction on the questionnaire: Multiple choice question #: ../tex_translations.in.h:18 msgid "Multiple-choice (select all applicable options)" msgstr "" #. Instruction on the questionnaire: Single choice question #: ../tex_translations.in.h:20 msgid "Single-choice (select only one option)" msgstr "" #. LaTeX based report: Label for the number of people that answered #: ../tex_translations.in.h:22 msgid "Answers" msgstr "Respostas" #. LaTeX based report: The calculated mean value #: ../tex_translations.in.h:24 msgid "Mean" msgstr "Média" #. LaTeX based report: The standard deviation #: ../tex_translations.in.h:26 msgid "Standard-Deviation" msgstr "Desvio Padrão" #~ msgid "Check" #~ msgstr "Marcar" #~ msgid "Uncheck to correct" #~ msgstr "Corrigir" #~ msgid "You can check any number of boxes in selection questions." #~ msgstr "Você pode marcar qualquer número de caixas em questões de seleção." #~ msgid "" #~ "For questions with a range (1--\\arabic{markcheckboxcount}) mark the " #~ "answer that fits best." #~ msgstr "" #~ "Em questões com um intervalo (1 - \\arabic{markcheckboxcount}) escolha a " #~ "resposta que se encaixa melhor." sdaps-1.9.8/tex/po/ro.po0000644000175000000660000000560413410742231015577 0ustar benjaminlock00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:09+0100\n" "PO-Revision-Date: 2018-10-04 13:52+0000\n" "Last-Translator: vgheo \n" "Language-Team: Romanian \n" "Language: ro\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < " "20)) ? 1 : 2;\n" "X-Generator: Weblate 3.2-dev\n" #. The language name of the LaTeX dictionary file for translator #: ../tex_translations.in.h:2 msgid "English" msgstr "Romanian" #. Used as an overlay for questionnaires that are not yet done #: ../tex_translations.in.h:4 msgid "draft" msgstr "ciornă" #. Label for the survey-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:6 msgid "Survey-ID:" msgstr "ID-Sondaj:" #. Label for the questionnaire-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:8 msgid "Questionnaire-ID:" msgstr "ID-Chestionar:" #. Default instructions on the questionnaire #: ../tex_translations.in.h:10 #, fuzzy msgid "" "This questionnaire is evaluated automatically. Please use a pen to fill in " "your answers as follows:" msgstr "" "Acest chestionar va fi citit automat de un program de calculator. Vă rugăm " "să folosiți un pix sau un stilou pentru a completa răspunsurile." #. Instruction on the questionnaire: Next to checked textbox #: ../tex_translations.in.h:12 msgid "Selected" msgstr "" #. Instruction on the questionnaire: Next to filled checkbox #: ../tex_translations.in.h:14 msgid "Fill to select" msgstr "" #. Instruction on the questionnaire: Next to filled and checked checkbox #: ../tex_translations.in.h:16 msgid "Undo select" msgstr "" #. Instruction on the questionnaire: Multiple choice question #: ../tex_translations.in.h:18 msgid "Multiple-choice (select all applicable options)" msgstr "" #. Instruction on the questionnaire: Single choice question #: ../tex_translations.in.h:20 msgid "Single-choice (select only one option)" msgstr "" #. LaTeX based report: Label for the number of people that answered #: ../tex_translations.in.h:22 msgid "Answers" msgstr "" #. LaTeX based report: The calculated mean value #: ../tex_translations.in.h:24 msgid "Mean" msgstr "" #. LaTeX based report: The standard deviation #: ../tex_translations.in.h:26 msgid "Standard-Deviation" msgstr "" #~ msgid "Check" #~ msgstr "Bifat" #~ msgid "Uncheck to correct" #~ msgstr "De-bifat pentru a corecta" #~ msgid "You can check any number of boxes in selection questions." #~ msgstr "La întrebările cu selecție puteți bifa orice număr de căsuțe." sdaps-1.9.8/tex/po/sdaps-tex.pot0000644000175000000660000000443013410742062017251 0ustar benjaminlock00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:10+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #. The language name of the LaTeX dictionary file for translator #: ../tex_translations.in.h:2 msgid "English" msgstr "" #. Used as an overlay for questionnaires that are not yet done #: ../tex_translations.in.h:4 msgid "draft" msgstr "" #. Label for the survey-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:6 msgid "Survey-ID:" msgstr "" #. Label for the questionnaire-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:8 msgid "Questionnaire-ID:" msgstr "" #. Default instructions on the questionnaire #: ../tex_translations.in.h:10 msgid "" "This questionnaire is evaluated automatically. Please use a pen to fill in " "your answers as follows:" msgstr "" #. Instruction on the questionnaire: Next to checked textbox #: ../tex_translations.in.h:12 msgid "Selected" msgstr "" #. Instruction on the questionnaire: Next to filled checkbox #: ../tex_translations.in.h:14 msgid "Fill to select" msgstr "" #. Instruction on the questionnaire: Next to filled and checked checkbox #: ../tex_translations.in.h:16 msgid "Undo select" msgstr "" #. Instruction on the questionnaire: Multiple choice question #: ../tex_translations.in.h:18 msgid "Multiple-choice (select all applicable options)" msgstr "" #. Instruction on the questionnaire: Single choice question #: ../tex_translations.in.h:20 msgid "Single-choice (select only one option)" msgstr "" #. LaTeX based report: Label for the number of people that answered #: ../tex_translations.in.h:22 msgid "Answers" msgstr "" #. LaTeX based report: The calculated mean value #: ../tex_translations.in.h:24 msgid "Mean" msgstr "" #. LaTeX based report: The standard deviation #: ../tex_translations.in.h:26 msgid "Standard-Deviation" msgstr "" sdaps-1.9.8/tex/po/si.po0000644000175000000660000000451613410742231015573 0ustar benjaminlock00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:09+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: si\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #. The language name of the LaTeX dictionary file for translator #: ../tex_translations.in.h:2 msgid "English" msgstr "Sinhala" #. Used as an overlay for questionnaires that are not yet done #: ../tex_translations.in.h:4 msgid "draft" msgstr "" #. Label for the survey-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:6 msgid "Survey-ID:" msgstr "" #. Label for the questionnaire-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:8 msgid "Questionnaire-ID:" msgstr "" #. Default instructions on the questionnaire #: ../tex_translations.in.h:10 msgid "" "This questionnaire is evaluated automatically. Please use a pen to fill in " "your answers as follows:" msgstr "" #. Instruction on the questionnaire: Next to checked textbox #: ../tex_translations.in.h:12 msgid "Selected" msgstr "" #. Instruction on the questionnaire: Next to filled checkbox #: ../tex_translations.in.h:14 msgid "Fill to select" msgstr "" #. Instruction on the questionnaire: Next to filled and checked checkbox #: ../tex_translations.in.h:16 msgid "Undo select" msgstr "" #. Instruction on the questionnaire: Multiple choice question #: ../tex_translations.in.h:18 msgid "Multiple-choice (select all applicable options)" msgstr "" #. Instruction on the questionnaire: Single choice question #: ../tex_translations.in.h:20 msgid "Single-choice (select only one option)" msgstr "" #. LaTeX based report: Label for the number of people that answered #: ../tex_translations.in.h:22 msgid "Answers" msgstr "" #. LaTeX based report: The calculated mean value #: ../tex_translations.in.h:24 msgid "Mean" msgstr "" #. LaTeX based report: The standard deviation #: ../tex_translations.in.h:26 msgid "Standard-Deviation" msgstr "" sdaps-1.9.8/tex/po/sv.po0000644000175000000660000000463413410742231015611 0ustar benjaminlock00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:09+0100\n" "PO-Revision-Date: 2014-09-19 15:16+0200\n" "Last-Translator: Benjamin Berg \n" "Language-Team: Swedish \n" "Language: sv\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 1.10-dev\n" #. The language name of the LaTeX dictionary file for translator #: ../tex_translations.in.h:2 msgid "English" msgstr "Swedish" #. Used as an overlay for questionnaires that are not yet done #: ../tex_translations.in.h:4 msgid "draft" msgstr "" #. Label for the survey-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:6 msgid "Survey-ID:" msgstr "" #. Label for the questionnaire-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:8 msgid "Questionnaire-ID:" msgstr "" #. Default instructions on the questionnaire #: ../tex_translations.in.h:10 msgid "" "This questionnaire is evaluated automatically. Please use a pen to fill in " "your answers as follows:" msgstr "" #. Instruction on the questionnaire: Next to checked textbox #: ../tex_translations.in.h:12 msgid "Selected" msgstr "" #. Instruction on the questionnaire: Next to filled checkbox #: ../tex_translations.in.h:14 msgid "Fill to select" msgstr "" #. Instruction on the questionnaire: Next to filled and checked checkbox #: ../tex_translations.in.h:16 msgid "Undo select" msgstr "" #. Instruction on the questionnaire: Multiple choice question #: ../tex_translations.in.h:18 msgid "Multiple-choice (select all applicable options)" msgstr "" #. Instruction on the questionnaire: Single choice question #: ../tex_translations.in.h:20 msgid "Single-choice (select only one option)" msgstr "" #. LaTeX based report: Label for the number of people that answered #: ../tex_translations.in.h:22 msgid "Answers" msgstr "" #. LaTeX based report: The calculated mean value #: ../tex_translations.in.h:24 msgid "Mean" msgstr "" #. LaTeX based report: The standard deviation #: ../tex_translations.in.h:26 msgid "Standard-Deviation" msgstr "" sdaps-1.9.8/tex/po/uk.po0000644000175000000660000000512313410742231015572 0ustar benjaminlock00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-12-26 19:09+0100\n" "PO-Revision-Date: 2018-01-31 17:41+0000\n" "Last-Translator: Марс Ямбар \n" "Language-Team: Ukrainian \n" "Language: uk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" "X-Generator: Weblate 2.19-dev\n" #. The language name of the LaTeX dictionary file for translator #: ../tex_translations.in.h:2 msgid "English" msgstr "Ukrainian" #. Used as an overlay for questionnaires that are not yet done #: ../tex_translations.in.h:4 msgid "draft" msgstr "чернетка" #. Label for the survey-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:6 msgid "Survey-ID:" msgstr "Опитування-ID:" #. Label for the questionnaire-id on the questionnaire (in "classic" mode) #: ../tex_translations.in.h:8 msgid "Questionnaire-ID:" msgstr "Анкета-ID:" #. Default instructions on the questionnaire #: ../tex_translations.in.h:10 msgid "" "This questionnaire is evaluated automatically. Please use a pen to fill in " "your answers as follows:" msgstr "" #. Instruction on the questionnaire: Next to checked textbox #: ../tex_translations.in.h:12 msgid "Selected" msgstr "" #. Instruction on the questionnaire: Next to filled checkbox #: ../tex_translations.in.h:14 msgid "Fill to select" msgstr "" #. Instruction on the questionnaire: Next to filled and checked checkbox #: ../tex_translations.in.h:16 msgid "Undo select" msgstr "" #. Instruction on the questionnaire: Multiple choice question #: ../tex_translations.in.h:18 msgid "Multiple-choice (select all applicable options)" msgstr "" #. Instruction on the questionnaire: Single choice question #: ../tex_translations.in.h:20 msgid "Single-choice (select only one option)" msgstr "" #. LaTeX based report: Label for the number of people that answered #: ../tex_translations.in.h:22 msgid "Answers" msgstr "" #. LaTeX based report: The calculated mean value #: ../tex_translations.in.h:24 msgid "Mean" msgstr "" #. LaTeX based report: The standard deviation #: ../tex_translations.in.h:26 msgid "Standard-Deviation" msgstr "Стандартне відхилення" sdaps-1.9.8/tex/sdapsreport.cls0000644000175000000660000002345413367301321017257 0ustar benjaminlock00000000000000%% start of file `sdapsreport.cls'. %% Copyright 2010-2011 Ferdinand Schwenk (ferdisdot@gmail.com). % % This work may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3c % of this license or (at your option) any later version. % The latest version of this license is in % http://www.latex-project.org/lppl.txt %------------------------------------------------------------------------------- % identification %------------------------------------------------------------------------------- \NeedsTeXFormat{LaTeX2e} \ProvidesClass{sdapsreport}[2011/12/20% v0.1 Class for SDAPS survey-report] %------------------------------------------------------------------------------- % debugging %------------------------------------------------------------------------------- \newif\if@DEBUG\@DEBUGfalse %------------------------------------------------------------------------------- % option processing %------------------------------------------------------------------------------- % pass unknown options to scrartcl \DeclareOption*{\PassOptionsToClass{\CurrentOption}{scrreprt}} % execute default options \ExecuteOptions{12pt,final} % process given options \ProcessOptions\relax %------------------------------------------------------------------------------- % load base-class %------------------------------------------------------------------------------- \LoadClass[twoside,headings=small]{scrreprt} %------------------------------------------------------------------------------- % required packages %------------------------------------------------------------------------------- % geometry package %\RequirePackage{geometry} %\geometry{hmargin=13mm} %\geometry{vmargin=25mm} %\geometry{top=21mm} %\geometry{bottom=25mm} % ifthen package \RequirePackage{ifthen} % ifpdf package \RequirePackage{ifpdf} % fontenc package \RequirePackage[T1]{fontenc} % color \RequirePackage{color} % hyperrefs \RequirePackage{url} \RequirePackage{hyperref} \hypersetup{% breaklinks,% baseurl = http://,% pdfborder = 0 0 0,% pdfpagemode = UseNone,% pdfcreator = \LaTeX{} with `sdapsreport' class,% pdfproducer = \LaTeX{} } \AtEndOfClass{% \AtBeginDocument{% \hypersetup{% pdfauthor = \@author,% pdftitle = \@title,% pdfsubject = sdaps report \@title,% pdfkeywords = sdaps report \@title% }% }% } % graphics \RequirePackage{graphicx} % headers and footers \usepackage{scrpage2} \clearscrheadings \chead[\@author\\\@title]{\@author\\\@title} \pagestyle{scrheadings} % Section formatting \RequirePackage{sectsty} % table of fixed width \RequirePackage{tabularx} % display content vertical centered \renewcommand\tabularxcolumn[1]{m{#1}} \newcolumntype{Y}{>{\raggedleft}X} % Einheiten \RequirePackage{siunitx} % Listen \RequirePackage{mdwlist} % Translation \RequirePackage{translator} \usedictionary{translator-sdaps-dictionary} % Zeichenprogramm \RequirePackage{tikz} \usetikzlibrary{calc} %------------------------------------------------------------------------------- % Declaration %------------------------------------------------------------------------------- \newcounter{question} \newlength{\boxheight} %------------------------------------------------------------------------------- % class definition %------------------------------------------------------------------------------- % minimal base settings \setlength\lineskip{1\p@} \setlength\normallineskip{1\p@} \renewcommand\baselinestretch{} \setlength{\parindent}{0pt} \setlength{\parskip}{0pt} \setlength\columnsep{10\p@} \setlength\columnseprule{0\p@} \pagestyle{scrheadings} \pagenumbering{arabic} \raggedbottom \onecolumn \newlength{\answerbarwidth} \setlength{\answerbarwidth}{0.5\linewidth} \newlength{\markdescwidth} \setlength{\markdescwidth}{0.49\linewidth} \newlength{\markdiawidth} \setlength{\markdiawidth}{0.5\linewidth} \newlength{\markbarheight} \setlength{\markbarheight}{3em} \definecolor{sdapschoicebarcolor}{gray}{0.6} \definecolor{sdapsmarkmeancolor}{gray}{0.0} \definecolor{sdapsmarkstddevcolor}{gray}{0.7} \definecolor{sdapsmarkbarcolor}{gray}{0.7} \definecolor{sdapsmarkbarframecolor}{gray}{0.0} \definecolor{sectionbgcolor}{gray}{0.8} \definecolor{sectionfgcolor}{gray}{0.0} %------------------------------------------------------------------------------- % style commands definitions %------------------------------------------------------------------------------- \def\smallskip{\vspace\smallskipamount} \def\medskip{\vspace\medskipamount} \def\bigskip{\vspace\bigskipamount} \newskip\smallskipamount \smallskipamount=3pt plus 1pt minus 1pt \newskip\medskipamount \medskipamount =6pt plus 2pt minus 2pt \newskip\bigskipamount \bigskipamount =12pt plus 4pt minus 4pt \setkomafont{descriptionlabel}{\normalfont} \newcommand{\sectbox}[1]{% \noindent\protect\colorbox{sectionbgcolor}{% \@tempdima=\hsize \advance\@tempdima by-2\fboxsep \protect\parbox{\@tempdima}{% \smallskip \raggedright % extra commands here \color{sectionfgcolor}\usekomafont{section}{#1} \smallskip }% }% } \sectionfont{\sectbox} \setkomafont{disposition}{\normalfont} \addtokomafont{section}{\bfseries\sffamily} \global\def\@extrainfos{} \newcommand{\addextrainfo}[2]{\global\edef\@extrainfos{\@extrainfos #1: & #2 \cr}}%\global\edef\@extrainfos{\@extrainfos #1 & #2 \\}} \renewcommand*\maketitle[1][1]{ \begin{titlepage}% \setcounter{page}{#1}% \null\vfill \begin{center}% \ifx\@subject\@empty \else {\Large \@subject \par}% \vskip 3em \fi {\titlefont\huge \@title\par}% \vskip 3em {\Large \lineskip 0.75em \begin{tabular}[t]{c}% \@author \end{tabular}\par}% \vskip 1.5em {\Large \@date \par}% \end{center} \vskip \z@ \@plus3fill \begin{tabular}[t]{rl}% \@extrainfos \end{tabular}% \end{titlepage}% \global\let\maketitle\relax \global\let\@author\@empty \global\let\@date\@empty \global\let\@title\@empty \global\let\@subject\@empty \global\let\@extrainfos\@empty \global\let\author\relax \global\let\title\relax \global\let\subject\relax \global\let\extrainfos\relax \global\let\date\relax \global\let\and\relax } %------------------------------------------------------------------------------- % structure commands definitions %------------------------------------------------------------------------------- \renewcommand{\author}[1]{\def\@author{#1}} \renewcommand{\title}[1]{\def\@title{#1}} \def\question{{\global\let\freeformsep\relax}\subsection*} \newcommand*{\decimaltopercent}[1]{ \pgfset{/pgf/number format/precision=0} \pgfmathparse{100 * #1} \pgfmathroundtozerofill{\pgfmathresult} \SI{\pgfmathresult}{\percent} } \newlength{\einheit} \newcommand*{\markdiagram}{% \begin{tikzpicture}[semithick] \pgfkeysgetvalue{/sdaps/mark/range}{\range} \pgfkeysgetvalue{/sdaps/mark/rangemin}{\rangemin} \pgfkeysgetvalue{/sdaps/mark/rangemax}{\rangemax} \pgfmathsetlength{\einheit}{\linewidth/\range} % note that we iter \key, not \x here; not sure why \x does not work. \foreach \key in {\rangemin,...,\rangemax} { \pgfmathsetmacro\x{\key + 1 - \rangemin} \pgfkeysgetvalue{/sdaps/mark/\key/fraction}{\val} \fill[xshift=\x\einheit,yshift=2pt, color=sdapsmarkbarcolor, draw=sdapsmarkbarframecolor, very thin] (-0.5\einheit, 0) rectangle (+0.5\einheit, \val\markbarheight); \node[above] at (\x\einheit, \markbarheight) {\decimaltopercent{\val}}; } \pgfmathparse{max(\pgfkeysvalueof{/sdaps/mark/mean}\einheit - % \pgfkeysvalueof{/sdaps/mark/stddev}\einheit, \einheit)} \pgfmathsetlength\@tempdima{\pgfmathresult} \pgfmathparse{min(\pgfkeysvalueof{/sdaps/mark/mean}\einheit + % \pgfkeysvalueof{/sdaps/mark/stddev}\einheit, \range\einheit)} \pgfmathsetlength\@tempdimb{\pgfmathresult} \fill[color=sdapsmarkstddevcolor] %Varianz (\@tempdima, 0ex) rectangle (\@tempdimb, -1ex); \draw[line width=2pt,color=sdapsmarkmeancolor,% xshift=\pgfkeysvalueof{/sdaps/mark/mean}\einheit] %Mittelwert (0, 0ex) -- (0, -1ex-1pt); \draw (+1.0\einheit,0ex) -- (\range\einheit,0ex); %Rahmen.Strich % \draw (+0.5\einheit,2pt) -- (5.5\einheit,2pt); %Rahmen.Strich \draw (+0.5\einheit,2pt) -- ($(\range\einheit,2pt) + (0.5\einheit,0)$); %Rahmen.Strich \foreach \x in {1,...,\range} \draw[xshift=\x\einheit] (0,0) -- (0, -1ex-1pt) node[below]{\footnotesize\x}; %Vert.Striche \end{tikzpicture} } \newenvironment{choicequestion}[1]{% \question{#1}% \tabularx{\linewidth}{Yrl} }{% \endtabularx% } \newenvironment{embedchoicequestion}{% \tabularx{\linewidth}{Yrl} }{% \endtabularx% } \newcommand*{\choiceanswer}[2]{% #1 & \decimaltopercent{#2} & \begin{tikzpicture} \fill[color=sdapschoicebarcolor] (0, 0) rectangle (#2\answerbarwidth, 1em); %Anteil \draw (0, 0) rectangle (\answerbarwidth, 1em); %Rahmen.Strich \end{tikzpicture}\\ } \newcommand*{\markanswer}{% \begin{minipage}[c]{\markdescwidth} \pgfkeysvalueof{/sdaps/mark/lower} -- \pgfkeysvalueof{/sdaps/mark/upper} \begin{description*} \item[\translate{answers}:] \pgfkeysvalueof{/sdaps/mark/count} \item[\translate{mean}:] \num{\pgfkeysvalueof{/sdaps/mark/mean}} \item[\translate{standard-deviation}:] \num{\pgfkeysvalueof{/sdaps/mark/stddev}} \end{description*} \end{minipage} \hfill \begin{minipage}[c]{\markdiawidth} \markdiagram \end{minipage} \\ } \let\freeformsep\relax \newcommand*{\freeform}[2]{% \freeformsep \pgfmathparse{min(#1, \linewidth)} \includegraphics[width=\pgfmathresult pt,keepaspectratio]{#2}\\ \def\freeformsep{\rule{\linewidth}{0.5pt}\\} } \newcommand*{\freeformtext}[1]{% \freeformsep #1\\ \def\freeformsep{\rule{\linewidth}{0.5pt}\\} } \endinput sdaps-1.9.8/tex/tex_translations.in0000644000175000000660000000345113410742231020130 0ustar benjaminlock00000000000000# Translations for sdaps LaTeX classes. # Copyright 2010-2013 Ferdinand Schwenk (ferdisdot@gmail.com). # Copyright 2011-2013 Benjamin Berg (benjamin@sipsolutions.net). # # This work may be distributed and/or modified under the # conditions of the LaTeX Project Public License, either version 1.3c # of this license or (at your option) any later version. # The latest version of this license is in # http://www.latex-project.org/lppl.txt # This file only exist to extract translations using intltool. # From this file the latex dictionary files are created at # build time. [translations] # The language name of the LaTeX dictionary file for translator _tex-language=English # Used as an overlay for questionnaires that are not yet done _draft=draft # Label for the survey-id on the questionnaire (in "classic" mode) _surveyid=Survey-ID: # Label for the questionnaire-id on the questionnaire (in "classic" mode) _questionnaireid=Questionnaire-ID: # Default instructions on the questionnaire _infotext=This questionnaire is evaluated automatically. Please use a pen to fill in your answers as follows: # Instruction on the questionnaire: Next to checked textbox _info-cross=Selected # Instruction on the questionnaire: Next to filled checkbox _info-fill=Fill to select # Instruction on the questionnaire: Next to filled and checked checkbox _info-corrected=Undo select # Instruction on the questionnaire: Multiple choice question _info-multi=Multiple-choice (select all applicable options) # Instruction on the questionnaire: Single choice question _info-single=Single-choice (select only one option) # LaTeX based report: Label for the number of people that answered _answers=Answers # LaTeX based report: The calculated mean value _mean=Mean # LaTeX based report: The standard deviation _standard-deviation=Standard-Deviation