├── anymeal ├── locale │ ├── .gitignore │ ├── Makefile.am │ ├── de │ │ └── Makefile.am │ ├── fr │ │ └── Makefile.am │ ├── it │ │ └── Makefile.am │ ├── nl │ │ └── Makefile.am │ └── sl │ │ └── Makefile.am ├── icon.rc ├── header.bmp ├── splash.png ├── splash.xcf ├── anymeal.ico ├── anymeal.png ├── .gitignore ├── flag_nl.svg ├── flag_fr.svg ├── flag_it.svg ├── de.wedesoft.anymeal.desktop ├── flag_de.svg ├── flag_uk.svg ├── anymeal.qrc ├── export.hh ├── ingredient.cc ├── partition.hh ├── export_dialog.hh ├── import_dialog.hh ├── mealmaster.hh ├── category_dialog.hh ├── add_dialog.hh ├── de.wedesoft.anymeal.appdata.xml ├── anymeal.cc ├── rename_dialog.hh ├── recipe.cc ├── category_picker.hh ├── categories_model.hh ├── merge_dialog.hh ├── category_dialog.cc ├── html.hh ├── converter_window.hh ├── anymeal.man ├── categories_model.cc ├── add_dialog.cc ├── titles_model.hh ├── recode.hh ├── partition.cc ├── flag_sl.svg ├── rename_dialog.cc ├── merge_dialog.cc ├── export_dialog.cc ├── import_dialog.cc ├── instructions_model.hh ├── ingredient.hh ├── titles_model.cc ├── category_table_model.hh ├── add_dialog.ui ├── merge_dialog.ui ├── rename_dialog.ui ├── edit_dialog.hh ├── ingredient_model.hh ├── category_dialog.ui ├── recipe.hh ├── Makefile.am ├── main_window.hh ├── recode.cc ├── category_picker.ui ├── category_picker.cc ├── database.hh ├── converter_window.ui ├── instructions_model.cc ├── category_table_model.cc ├── duplicate.svg ├── export_dialog.ui ├── import_dialog.ui └── export.cc ├── debian ├── clean ├── source │ └── format ├── rules ├── upstream │ ├── metadata │ └── signing-key.asc ├── watch ├── control └── copyright ├── tests ├── .gitignore ├── fixtures │ ├── no_servings.mmf │ ├── serving_spaces.mmf │ ├── header.mmf │ ├── instructions10.mmf │ ├── instructions5.mmf │ ├── instructions6.mmf │ ├── instructions7.mmf │ ├── instructions8.mmf │ ├── header2.mmf │ ├── instructions2.mmf │ ├── instructions9.mmf │ ├── title_spaces.mmf │ ├── instructions3.mmf │ ├── instructions4.mmf │ ├── no_ingredient.mmf │ ├── instructions1.mmf │ ├── float.mmf │ ├── ignore_0x14.mmf │ ├── mixed.mmf │ ├── replace_0x9.mmf │ ├── fraction.mmf │ ├── noamount.mmf │ ├── append_to_line.mmf │ ├── ingredient.mmf │ ├── two_instructions.mmf │ ├── ingredient_like.mmf │ ├── preparation.mmf │ ├── overlong_ingredient.mmf │ ├── overlong_ingredient2.mmf │ ├── skip_leading_spaces.mmf │ ├── unexpected_continuation.mmf │ ├── two_columns.mmf │ ├── float_crlf.mmf │ ├── two_ingredients.mmf │ ├── force_newline.mmf │ ├── instruction_eol.mmf │ ├── instruction_eol2.mmf │ ├── instruction_eol3.mmf │ ├── instruction_number.mmf │ ├── stray_ingredient.mmf │ ├── continuation.mmf │ ├── ignore_whitespaces.mmf │ ├── instruction_eol4.mmf │ ├── continuation_whitespace.mmf │ ├── discard_two_spaces.mmf │ ├── flush_ingredients.mmf │ ├── three_ingredients.mmf │ ├── section_whitespace.mmf │ ├── column_major.mmf │ ├── two_column_continuation4.mmf │ ├── two_column_trailing.mmf │ ├── two_column_continuation.mmf │ ├── two_column_continuation2.mmf │ ├── two_column_continuation3.mmf │ ├── instruction_section.mmf │ ├── section_hyphen.mmf │ ├── section_spaces.mmf │ ├── ingredient_section.mmf │ ├── instruction_header.mmf │ ├── erroneous_continuation.mmf │ ├── ignore_newlines.mmf │ ├── empty_ingredient_section.mmf │ ├── two_column_section.mmf │ └── Makefile.am ├── suite.cc ├── test_ingredient.cc ├── Makefile.am ├── test_recipe.cc ├── test_partition.cc └── test_recode.cc ├── autogen.sh ├── m4 ├── .gitignore └── ax_lib_sqlite3.m4 ├── Makefile.am ├── etc ├── dput.cf ├── docker-compose.yml └── Dockerfile ├── .gitignore ├── configure.mingw ├── Makefile.package ├── Makefile.appimage ├── Dockerfile.sid ├── snapcraft.yaml ├── Makefile.sid ├── configure.ac ├── .github └── workflows │ └── anymeal.yml ├── README.md └── anymeal.nsi /anymeal/locale/.gitignore: -------------------------------------------------------------------------------- 1 | *.qm 2 | -------------------------------------------------------------------------------- /debian/clean: -------------------------------------------------------------------------------- 1 | tests/gtest-all.cc 2 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /anymeal/icon.rc: -------------------------------------------------------------------------------- 1 | anymeal ICON "anymeal.ico" 2 | -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | gmock-all.cc 2 | gtest-all.cc 3 | -------------------------------------------------------------------------------- /anymeal/locale/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = de it nl fr sl 2 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | git log > ChangeLog 3 | autoreconf -i 4 | -------------------------------------------------------------------------------- /anymeal/header.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wedesoft/anymeal/HEAD/anymeal/header.bmp -------------------------------------------------------------------------------- /anymeal/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wedesoft/anymeal/HEAD/anymeal/splash.png -------------------------------------------------------------------------------- /anymeal/splash.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wedesoft/anymeal/HEAD/anymeal/splash.xcf -------------------------------------------------------------------------------- /anymeal/anymeal.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wedesoft/anymeal/HEAD/anymeal/anymeal.ico -------------------------------------------------------------------------------- /anymeal/anymeal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wedesoft/anymeal/HEAD/anymeal/anymeal.png -------------------------------------------------------------------------------- /anymeal/.gitignore: -------------------------------------------------------------------------------- 1 | anymeal 2 | mealmaster.cc 3 | lib*.a 4 | moc_*.cc 5 | ui_*.hh 6 | qrc_*.cc 7 | -------------------------------------------------------------------------------- /m4/.gitignore: -------------------------------------------------------------------------------- 1 | libtool.m4 2 | ltoptions.m4 3 | ltsugar.m4 4 | ltversion.m4 5 | lt~obsolete.m4 6 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = -I m4 2 | 3 | SUBDIRS = anymeal tests 4 | 5 | doc_DATA = README.md 6 | 7 | EXTRA_DIST = README.md LICENSE anymeal.nsi 8 | -------------------------------------------------------------------------------- /tests/fixtures/no_servings.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | 5 | MMMMM 6 | -------------------------------------------------------------------------------- /tests/fixtures/serving_spaces.mmf: -------------------------------------------------------------------------------- 1 | ---------- Recipe via Meal-Master (tm) v7.04 2 | 3 | Title: Hearty Russian Beet Soup 4 | Categories: Soups 5 | Servings: 8 6 | 7 | ----- 8 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | export DH_VERBOSE = 1 4 | export DEB_BUILD_MAINT_OPTIONS = hardening=+all 5 | export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic 6 | 7 | %: 8 | dh $@ 9 | -------------------------------------------------------------------------------- /tests/fixtures/header.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Servings: 42 pies 5 | MMMMM 6 | -------------------------------------------------------------------------------- /tests/fixtures/instructions10.mmf: -------------------------------------------------------------------------------- 1 | ---------- Recipe via Meal-Master (tm) v8.05 2 | 3 | Title: cooked apple 4 | Categories: desserts 5 | Yield: 1 Servings 6 | 7 | 1 2/3 each. 8 | ----- 9 | -------------------------------------------------------------------------------- /tests/fixtures/instructions5.mmf: -------------------------------------------------------------------------------- 1 | ---------- Recipe via Meal-Master (tm) v8.05 2 | 3 | Title: cooked apple 4 | Categories: desserts 5 | Yield: 1 Servings 6 | 7 | - 8 | ----- 9 | -------------------------------------------------------------------------------- /tests/fixtures/instructions6.mmf: -------------------------------------------------------------------------------- 1 | ---------- Recipe via Meal-Master (tm) v8.05 2 | 3 | Title: cooked apple 4 | Categories: desserts 5 | Yield: 1 Servings 6 | 7 | 2 3 apples. 8 | ----- 9 | -------------------------------------------------------------------------------- /tests/fixtures/instructions7.mmf: -------------------------------------------------------------------------------- 1 | ---------- Recipe via Meal-Master (tm) v8.05 2 | 3 | Title: cooked apple 4 | Categories: desserts 5 | Yield: 1 Servings 6 | 7 | 1/x apples. 8 | ----- 9 | -------------------------------------------------------------------------------- /tests/fixtures/instructions8.mmf: -------------------------------------------------------------------------------- 1 | ---------- Recipe via Meal-Master (tm) v8.05 2 | 3 | Title: cooked apple 4 | Categories: desserts 5 | Yield: 1 Servings 6 | 7 | 1/2 apples. 8 | ----- 9 | -------------------------------------------------------------------------------- /tests/fixtures/header2.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Yield: 42 servings 5 | MMMMM 6 | -------------------------------------------------------------------------------- /tests/fixtures/instructions2.mmf: -------------------------------------------------------------------------------- 1 | ---------- Recipe via Meal-Master (tm) v8.05 2 | 3 | Title: cooked apple 4 | Categories: desserts 5 | Yield: 1 Servings 6 | 7 | 1 cook is used. 8 | ----- 9 | -------------------------------------------------------------------------------- /tests/fixtures/instructions9.mmf: -------------------------------------------------------------------------------- 1 | ---------- Recipe via Meal-Master (tm) v8.05 2 | 3 | Title: cooked apple 4 | Categories: desserts 5 | Yield: 1 Servings 6 | 7 | 1 2/x apples. 8 | ----- 9 | -------------------------------------------------------------------------------- /tests/fixtures/title_spaces.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Servings: 42 pies 5 | MMMMM 6 | -------------------------------------------------------------------------------- /tests/fixtures/instructions3.mmf: -------------------------------------------------------------------------------- 1 | ---------- Recipe via Meal-Master (tm) v8.05 2 | 3 | Title: cooked apple 4 | Categories: desserts 5 | Yield: 1 Servings 6 | 7 | Start cooking. 8 | ----- 9 | -------------------------------------------------------------------------------- /tests/fixtures/instructions4.mmf: -------------------------------------------------------------------------------- 1 | ---------- Recipe via Meal-Master (tm) v8.05 2 | 3 | Title: cooked apple 4 | Categories: desserts 5 | Yield: 1 Servings 6 | 7 | 2.5 apples are used. 8 | ----- 9 | -------------------------------------------------------------------------------- /tests/fixtures/no_ingredient.mmf: -------------------------------------------------------------------------------- 1 | ---------- Recipe via Meal-Master (tm) v8.01 2 | 3 | Title: Carrot Cake 4 | Categories: Cakes, Muffins 5 | Yield: 12 servings 6 | 7 | 20 mg cholesterol 8 | ----- 9 | -------------------------------------------------------------------------------- /tests/fixtures/instructions1.mmf: -------------------------------------------------------------------------------- 1 | ---------- Recipe via Meal-Master (tm) v8.05 2 | 3 | Title: cooked apple 4 | Categories: desserts 5 | Yield: 1 Servings 6 | 7 | Cook all the ingredients. 8 | ----- 9 | -------------------------------------------------------------------------------- /tests/fixtures/float.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Servings: 42 pies 5 | 6 | 2.5 g butter 7 | MMMMM 8 | -------------------------------------------------------------------------------- /tests/fixtures/ignore_0x14.mmf: -------------------------------------------------------------------------------- 1 | ---------- Recipe via Meal-Master (tm) v7.04 2 | 3 | Title: Nora Mill Whole Wheat Pancakes 4 | Categories: Cakes 5 | Servings: 8 6 | 7 | First line. 8 | 9 | ----- 10 | -------------------------------------------------------------------------------- /tests/fixtures/mixed.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Servings: 42 pies 5 | 6 | 1 2/3 g fat 7 | MMMMM 8 | -------------------------------------------------------------------------------- /tests/fixtures/replace_0x9.mmf: -------------------------------------------------------------------------------- 1 | ---------- Recipe via Meal-Master (tm) v7.04 2 | 3 | Title: Nora Mill Whole Wheat Pancakes 4 | Categories: Cakes 5 | Servings: 8 6 | 7 | First line. 8 | 9 | ----- 10 | -------------------------------------------------------------------------------- /etc/dput.cf: -------------------------------------------------------------------------------- 1 | [mentors] 2 | fqdn = mentors.debian.net 3 | incoming = /upload 4 | method = https 5 | allow_unsigned_uploads = 0 6 | progress_indicator = 2 7 | # Allow uploads for UNRELEASED packages 8 | allowed_distributions = .* 9 | -------------------------------------------------------------------------------- /tests/fixtures/fraction.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Servings: 42 pies 5 | 6 | 2/3 c olive oil 7 | MMMMM 8 | -------------------------------------------------------------------------------- /tests/fixtures/noamount.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Servings: 42 pies 5 | 6 | butter 7 | MMMMM 8 | -------------------------------------------------------------------------------- /tests/fixtures/append_to_line.mmf: -------------------------------------------------------------------------------- 1 | ---------- Recipe via Meal-Master (tm) v8.05 2 | 3 | Title: cooked apple 4 | Categories: desserts 5 | Yield: 1 Servings 6 | 7 | First part. 8 | Second part. 9 | ----- 10 | 11 | -------------------------------------------------------------------------------- /tests/fixtures/ingredient.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Servings: 42 pies 5 | 6 | 250 g brown flour 7 | MMMMM 8 | -------------------------------------------------------------------------------- /tests/fixtures/two_instructions.mmf: -------------------------------------------------------------------------------- 1 | ---------- Recipe via Meal-Master (tm) v8.05 2 | 3 | Title: cooked apple 4 | Categories: desserts 5 | Yield: 1 Servings 6 | 7 | First line. 8 | 9 | Third line. 10 | ----- 11 | -------------------------------------------------------------------------------- /etc/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | app: 5 | image: anymeal:latest 6 | environment: 7 | - DISPLAY=${DISPLAY} 8 | volumes: 9 | - /tmp/.X11-unix:/tmp/.X11-unix 10 | network_mode: host 11 | -------------------------------------------------------------------------------- /tests/fixtures/ingredient_like.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Servings: 42 pies 5 | 6 | First line 7 | 1 kg water. 8 | MMMMM 9 | -------------------------------------------------------------------------------- /tests/fixtures/preparation.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Servings: 42 pies 5 | 6 | 250 g brown flour; sifted 7 | MMMMM 8 | -------------------------------------------------------------------------------- /tests/fixtures/overlong_ingredient.mmf: -------------------------------------------------------------------------------- 1 | ---------- Recipe via Meal-Master (tm) v8.01 2 | 3 | Title: Carrot Cake 4 | Categories: Cakes, Muffins 5 | Yield: 12 servings 6 | 7 | 100 2/3 ts abcdefghijklmnopqrstuvwxyzabc defghijk 8 | ----- 9 | -------------------------------------------------------------------------------- /tests/fixtures/overlong_ingredient2.mmf: -------------------------------------------------------------------------------- 1 | ---------- Recipe via Meal-Master (tm) v8.01 2 | 3 | Title: Carrot Cake 4 | Categories: Cakes, Muffins 5 | Yield: 12 servings 6 | 7 | 100 2/3 ts abcdefghijklmnopqrstuvwxyzabcdefghijk 8 | ----- 9 | -------------------------------------------------------------------------------- /tests/fixtures/skip_leading_spaces.mmf: -------------------------------------------------------------------------------- 1 | 2 | ---------- Recipe via Meal-Master (tm) v8.05 3 | 4 | Title: cooked apple 5 | Categories: desserts 6 | Yield: 1 Servings 7 | 8 | First part. 9 | Second part. 10 | ----- 11 | 12 | -------------------------------------------------------------------------------- /tests/fixtures/unexpected_continuation.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Servings: 42 pies 5 | 6 | -John Doe- 7 | MMMMM 8 | -------------------------------------------------------------------------------- /anymeal/flag_nl.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /tests/fixtures/two_columns.mmf: -------------------------------------------------------------------------------- 1 | ---------- Recipe via Meal-Master (tm) v8.01 2 | 3 | Title: Carrot Cake 4 | Categories: Cakes, Muffins 5 | Yield: 12 servings 6 | 7 | 100 2/3 c Oil 100 2/3 ts Baking soda 8 | ----- 9 | -------------------------------------------------------------------------------- /debian/upstream/metadata: -------------------------------------------------------------------------------- 1 | Name: anymeal 2 | Contact: Jan Wedekind 3 | Repository: https://github.com/wedesoft/anymeal.git 4 | Repository-Browse: https://github.com/wedesoft/anymeal 5 | Bug-Database: https://github.com/wedesoft/anymeal/issues 6 | -------------------------------------------------------------------------------- /tests/fixtures/float_crlf.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Servings: 42 pies 5 | 6 | Posted on Apr 27, 7 | 1998. 8 | 9 | MMMMM 10 | -------------------------------------------------------------------------------- /tests/fixtures/two_ingredients.mmf: -------------------------------------------------------------------------------- 1 | ---------- Recipe via Meal-Master (tm) v8.05 2 | 3 | Title: "21" Club Rice Pudding 4 | Categories: Dessert 5 | Yield: 10 Servings 6 | 7 | 1 qt pastry 8 | 6 c cooking apple 9 | ----- 10 | -------------------------------------------------------------------------------- /tests/fixtures/force_newline.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Servings: 42 pies 5 | 6 | First line. 7 | :Second line. 8 | 9 | MMMMM 10 | -------------------------------------------------------------------------------- /tests/fixtures/instruction_eol.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Servings: 42 pies 5 | 6 | Posted on Apr 27, 7 | 1998. 8 | 9 | MMMMM 10 | -------------------------------------------------------------------------------- /tests/fixtures/instruction_eol2.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Servings: 42 pies 5 | 6 | Posted on Apr 27, 7 | 1 2 8 | 9 | MMMMM 10 | -------------------------------------------------------------------------------- /tests/fixtures/instruction_eol3.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Servings: 42 pies 5 | 6 | Posted on Apr 27, 7 | 1/ 8 | 9 | MMMMM 10 | -------------------------------------------------------------------------------- /tests/fixtures/instruction_number.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Servings: 42 pies 5 | 6 | Posted on Apr 27, 7 | 1998 8 | 9 | MMMMM 10 | -------------------------------------------------------------------------------- /tests/fixtures/stray_ingredient.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Servings: 42 pies 5 | 6 | First line. 7 | 200.0 ml milk 8 | 9 | MMMMM 10 | -------------------------------------------------------------------------------- /tests/fixtures/continuation.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Servings: 42 pies 5 | 6 | 2.5 g butter; molten 7 | -and stirred 8 | MMMMM 9 | -------------------------------------------------------------------------------- /tests/fixtures/ignore_whitespaces.mmf: -------------------------------------------------------------------------------- 1 | ---------- Recipe via Meal-Master (tm) v8.05 2 | 3 | Title: "21" Club Rice Pudding 4 | Categories: Dessert 5 | Yield: 10 Servings 6 | 7 | 1 qt pastry 8 | 6 c cooking apple 9 | ----- 10 | 11 | -------------------------------------------------------------------------------- /tests/fixtures/instruction_eol4.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Servings: 42 pies 5 | 6 | Posted on Apr 27, 7 | 1998. 8 | 9 | MMMMM 10 | -------------------------------------------------------------------------------- /anymeal/flag_fr.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /tests/fixtures/continuation_whitespace.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Servings: 42 pies 5 | 6 | 2.5 g butter; molten 7 | - and stirred 8 | MMMMM 9 | -------------------------------------------------------------------------------- /tests/fixtures/discard_two_spaces.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries 4 | Servings: 42 pies 5 | 6 | Only discard 7 | two 8 | leading spaces. 9 | MMMMM 10 | -------------------------------------------------------------------------------- /tests/fixtures/flush_ingredients.mmf: -------------------------------------------------------------------------------- 1 | 2 | ---------- Recipe via Meal-Master (tm) v8.01 3 | 4 | Title: Carrot Cake 5 | Categories: Cakes, Muffins 6 | Yield: 12 servings 7 | 8 | 1 c ingredient1 1 ts ingredient2 9 | 10 | 1 cup. 11 | ----- 12 | 13 | 14 | -------------------------------------------------------------------------------- /tests/fixtures/three_ingredients.mmf: -------------------------------------------------------------------------------- 1 | ---------- Recipe via Meal-Master (tm) v8.01 2 | 3 | Title: Carrot Cake 4 | Categories: Cakes, Muffins 5 | Yield: 12 servings 6 | 7 | 1 c ingredient1 1 ts ingredient3 8 | 1 c ingredient2 9 | ----- 10 | 11 | 12 | -------------------------------------------------------------------------------- /anymeal/flag_it.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /debian/watch: -------------------------------------------------------------------------------- 1 | version=4 2 | 3 | opts=downloadurlmangle=s/archive\/refs\/tags\/v(.*)\.tar\.gz/releases\/download\/v$1\/anymeal-$1\.tar\.xz/,\ 4 | pgpsigurlmangle=s/$/.asc/,\ 5 | dversionmangle=s/\+dfsg1//,repacksuffix=+dfsg1 \ 6 | https://github.com/wedesoft/anymeal/tags \ 7 | /wedesoft/anymeal/archive/refs/tags/v(.*)\.tar\.gz 8 | -------------------------------------------------------------------------------- /tests/fixtures/section_whitespace.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Servings: 42 pies 5 | 6 | MMMMM-------------------------------meringue------------------------------- 7 | First line. 8 | 9 | MMMMM 10 | -------------------------------------------------------------------------------- /tests/fixtures/column_major.mmf: -------------------------------------------------------------------------------- 1 | ---------- Recipe via Meal-Master (tm) v8.01 2 | 3 | Title: Carrot Cake 4 | Categories: Cakes, Muffins 5 | Yield: 12 servings 6 | 7 | 1 c ingredient1 1 ts ingredient3 8 | 1 c ingredient2 1 ts ingredient4 9 | ----- 10 | -------------------------------------------------------------------------------- /tests/fixtures/two_column_continuation4.mmf: -------------------------------------------------------------------------------- 1 | ---------- Recipe via Meal-Master (tm) v8.01 2 | 3 | Title: Carrot Cake 4 | Categories: Cakes, Muffins 5 | Yield: 12 servings 6 | 7 | 1 c ingredient1 -cont_b 8 | -cont_a -cont_c 9 | ----- 10 | -------------------------------------------------------------------------------- /tests/fixtures/two_column_trailing.mmf: -------------------------------------------------------------------------------- 1 | ---------- Recipe via Meal-Master (tm) v8.01 2 | 3 | Title: Hollandaise Sauce 4 | Categories: Sauces 5 | Yield: 1 servings 6 | 7 | 2 tb lemon juice 8 | 9 | In small saucepan with wire whisk beat all ingredients until smooth. 10 | 11 | ----- 12 | -------------------------------------------------------------------------------- /anymeal/locale/de/Makefile.am: -------------------------------------------------------------------------------- 1 | SUFFIXES = .ts .qm 2 | 3 | dedir = $(localedir)/de/LC_MESSAGES 4 | de_DATA = anymeal_qt.qm 5 | 6 | EXTRA_DIST = anymeal_qt.ts 7 | 8 | CLEANFILES = anymeal_qt.qm 9 | 10 | %.ts: $(wildcard ../../*.cc) $(wildcard ../../*.ui) 11 | $(QT_LUPDATE) $^ -ts $@ 12 | 13 | .ts.qm: 14 | $(QT_LCONVERT) -o $@ $< 15 | -------------------------------------------------------------------------------- /anymeal/locale/fr/Makefile.am: -------------------------------------------------------------------------------- 1 | SUFFIXES = .ts .qm 2 | 3 | frdir = $(localedir)/fr/LC_MESSAGES 4 | fr_DATA = anymeal_qt.qm 5 | 6 | EXTRA_DIST = anymeal_qt.ts 7 | 8 | CLEANFILES = anymeal_qt.qm 9 | 10 | %.ts: $(wildcard ../../*.cc) $(wildcard ../../*.ui) 11 | $(QT_LUPDATE) $^ -ts $@ 12 | 13 | .ts.qm: 14 | $(QT_LCONVERT) -o $@ $< 15 | -------------------------------------------------------------------------------- /anymeal/locale/it/Makefile.am: -------------------------------------------------------------------------------- 1 | SUFFIXES = .ts .qm 2 | 3 | itdir = $(localedir)/it/LC_MESSAGES 4 | it_DATA = anymeal_qt.qm 5 | 6 | EXTRA_DIST = anymeal_qt.ts 7 | 8 | CLEANFILES = anymeal_qt.qm 9 | 10 | %.ts: $(wildcard ../../*.cc) $(wildcard ../../*.ui) 11 | $(QT_LUPDATE) $^ -ts $@ 12 | 13 | .ts.qm: 14 | $(QT_LCONVERT) -o $@ $< 15 | -------------------------------------------------------------------------------- /anymeal/locale/nl/Makefile.am: -------------------------------------------------------------------------------- 1 | SUFFIXES = .ts .qm 2 | 3 | nldir = $(localedir)/nl/LC_MESSAGES 4 | nl_DATA = anymeal_qt.qm 5 | 6 | EXTRA_DIST = anymeal_qt.ts 7 | 8 | CLEANFILES = anymeal_qt.qm 9 | 10 | %.ts: $(wildcard ../../*.cc) $(wildcard ../../*.ui) 11 | $(QT_LUPDATE) $^ -ts $@ 12 | 13 | .ts.qm: 14 | $(QT_LCONVERT) -o $@ $< 15 | -------------------------------------------------------------------------------- /anymeal/locale/sl/Makefile.am: -------------------------------------------------------------------------------- 1 | SUFFIXES = .ts .qm 2 | 3 | sldir = $(localedir)/sl/LC_MESSAGES 4 | sl_DATA = anymeal_qt.qm 5 | 6 | EXTRA_DIST = anymeal_qt.ts 7 | 8 | CLEANFILES = anymeal_qt.qm 9 | 10 | %.ts: $(wildcard ../../*.cc) $(wildcard ../../*.ui) 11 | $(QT_LUPDATE) $^ -ts $@ 12 | 13 | .ts.qm: 14 | $(QT_LCONVERT) -o $@ $< 15 | -------------------------------------------------------------------------------- /tests/fixtures/two_column_continuation.mmf: -------------------------------------------------------------------------------- 1 | ---------- Recipe via Meal-Master (tm) v8.01 2 | 3 | Title: Carrot Cake 4 | Categories: Cakes, Muffins 5 | Yield: 12 servings 6 | 7 | 1 c ingredient1 1 ts ingredient3 8 | 1 c ingredient2 -continued 9 | ----- 10 | -------------------------------------------------------------------------------- /tests/fixtures/two_column_continuation2.mmf: -------------------------------------------------------------------------------- 1 | ---------- Recipe via Meal-Master (tm) v8.01 2 | 3 | Title: Carrot Cake 4 | Categories: Cakes, Muffins 5 | Yield: 12 servings 6 | 7 | 1 c ingredient1 1 ts ingredient2 8 | -continued 1 tb ingredient3 9 | ----- 10 | -------------------------------------------------------------------------------- /tests/fixtures/two_column_continuation3.mmf: -------------------------------------------------------------------------------- 1 | ---------- Recipe via Meal-Master (tm) v8.01 2 | 3 | Title: Carrot Cake 4 | Categories: Cakes, Muffins 5 | Yield: 12 servings 6 | 7 | 1 c ingredient1 -continued 8 | 1 ts ingredient2 1 tb ingredient3 9 | ----- 10 | -------------------------------------------------------------------------------- /tests/fixtures/instruction_section.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Servings: 42 pies 5 | 6 | First line. 7 | MMMMM-------------------------------meringue-------------------------------- 8 | Second line. 9 | 10 | MMMMM 11 | -------------------------------------------------------------------------------- /tests/fixtures/section_hyphen.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Servings: 42 pies 5 | 6 | 250 g brown flour 7 | MMMMM----------------------------section-hyphen----------------------------- 8 | 150 g sugar 9 | MMMMM 10 | -------------------------------------------------------------------------------- /tests/fixtures/section_spaces.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Servings: 42 pies 5 | 6 | 250 g brown flour 7 | MMMMM--------------------------- section spaces ---------------------------- 8 | 150 g sugar 9 | MMMMM 10 | -------------------------------------------------------------------------------- /anymeal/de.wedesoft.anymeal.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=anymeal 3 | GenericName=Recipe Manager 4 | Comment=Free recipe management software 5 | Keywords=recipes;cooking;database; 6 | StartupWMClass=anymeal 7 | StartupNotify=false 8 | Exec=anymeal 9 | Terminal=false 10 | Type=Application 11 | Icon=anymeal 12 | Categories=Qt;Utility;Viewer; 13 | -------------------------------------------------------------------------------- /tests/fixtures/ingredient_section.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Servings: 42 pies 5 | 6 | 250 g brown flour 7 | MMMMM-------------------------------meringue-------------------------------- 8 | 150 g sugar 9 | MMMMM 10 | -------------------------------------------------------------------------------- /tests/fixtures/instruction_header.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Servings: 42 pies 5 | 6 | Ingredient 7 | 8 | MMMMM-------------------------------meringue-------------------------------- 9 | First line. 10 | 11 | MMMMM 12 | -------------------------------------------------------------------------------- /tests/fixtures/erroneous_continuation.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Servings: 42 pies 5 | 6 | 2.5 g butter; molten 7 | MMMMM-------------------------------meringue-------------------------------- 8 | -and stirred 9 | MMMMM 10 | -------------------------------------------------------------------------------- /tests/fixtures/ignore_newlines.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Servings: 42 pies 5 | 6 | First line. 7 | 8 | Third line. 9 | 10 | MMMMM------------------------------- section ------------------------------- 11 | Fourth line. 12 | 13 | 14 | Sixth line. 15 | 16 | MMMMM 17 | -------------------------------------------------------------------------------- /tests/fixtures/empty_ingredient_section.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Servings: 42 pies 5 | 6 | 250 g brown flour 7 | MMMMM--------------------------------empty---------------------------------- 8 | MMMMM-------------------------------meringue-------------------------------- 9 | 150 g sugar 10 | MMMMM 11 | -------------------------------------------------------------------------------- /tests/fixtures/two_column_section.mmf: -------------------------------------------------------------------------------- 1 | MMMMM----------------Meal-Master recipe exported by AnyMeal----------------- 2 | Title: apple pie 3 | Categories: pastries, cakes 4 | Servings: 42 pies 5 | 6 | 1 c ingredient1 1 ts ingredient2 7 | MMMMM-------------------------------meringue-------------------------------- 8 | 1 c ingredient3 1 ts ingredient4 9 | MMMMM 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .deps 2 | .libs 3 | AppDir 4 | ChangeLog 5 | Makefile 6 | Makefile.in 7 | aclocal.m4 8 | autom4te.cache 9 | compile 10 | config.guess 11 | config.h 12 | config.h.in 13 | config.h.in~ 14 | config.log 15 | config.status 16 | config.sub 17 | configure 18 | depcomp 19 | docker 20 | install-sh 21 | libtool 22 | ltmain.sh 23 | missing 24 | pkg 25 | stamp-h1 26 | suite 27 | ylwrap 28 | *.AppImage 29 | *.xz 30 | *.asc 31 | *.o 32 | *.exe 33 | -------------------------------------------------------------------------------- /configure.mingw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ./configure --prefix=/mingw64 --with-sqlite3=/mingw64 --with-x=no --with-gtest=/c/msys64/mingw64/src/gtest LIBS="-Wl,-subsystem,windows -L/mingw64/lib -lQt6Core -lQt6Widgets -lQt6Gui -lQt6PrintSupport -lQt6Svg -liconv" CFLAGS=-I/mingw64/include CXXFLAGS="-I/mingw64/include -I/mingw64/include/qt6 -I/mingw64/include/qt6/QtCore -I/mingw64/include/qt6/QtGui -I/mingw64/include/qt6/QtPrintSupport -I/mingw64/include/qt6/QtSvg -I/mingw64/include/qt6/QtWidgets" 3 | -------------------------------------------------------------------------------- /anymeal/flag_de.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Flag of Germany 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Makefile.package: -------------------------------------------------------------------------------- 1 | # https://wiki.debian.org/IntroDebianPackaging 2 | # https://en.opensuse.org/openSUSE:Build_Service_Tutorial 3 | 4 | VERSION=$(shell grep AC_INIT configure.ac | sed -e "s/.*\[\([0-9\.]*\)\].*/\1/") 5 | 6 | package: anymeal.tar.xz anymeal.tar.xz.asc 7 | mkdir -p pkg 8 | cp anymeal.tar.xz pkg/anymeal_$(VERSION).orig.tar.xz 9 | cp anymeal.tar.xz.asc pkg/anymeal_$(VERSION).orig.tar.xz.asc 10 | tar xf anymeal.tar.xz -C pkg 11 | cp -a debian pkg/anymeal-$(VERSION) 12 | cd pkg/anymeal-$(VERSION) && debuild -us -uc -j4 && cd ../.. 13 | -------------------------------------------------------------------------------- /etc/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:sid 2 | LABEL maintainer="Jan Wedekind " 3 | RUN echo "deb http://httpredir.debian.org/debian unstable main" > /etc/apt/sources.list 4 | RUN apt-get update # Forced update Fri 20 Sep 15:16:57 BST 2024 5 | RUN apt-get -q -y dist-upgrade 6 | RUN apt-get install -y xauth 7 | ADD anymeal_1.34-1_amd64.deb anymeal_1.34-1_amd64.deb 8 | RUN apt install -y ./anymeal_1.34-1_amd64.deb 9 | # get string with xauth list 10 | RUN xauth add wedetux/unix:1 MIT-MAGIC-COOKIE-1 6cb65c8a386b1ddd7652b3656de94a95 11 | CMD ["anymeal"] 12 | -------------------------------------------------------------------------------- /anymeal/flag_uk.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /anymeal/anymeal.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | duplicate.svg 4 | down.svg 5 | up.svg 6 | calculator.svg 7 | categoryadd.svg 8 | edit.svg 9 | search.svg 10 | categoryremove.svg 11 | trash.svg 12 | splash.png 13 | delete.svg 14 | import.svg 15 | export.svg 16 | preview.svg 17 | print.svg 18 | quit.svg 19 | anymeal.png 20 | new.svg 21 | flag_uk.svg 22 | flag_de.svg 23 | flag_fr.svg 24 | flag_it.svg 25 | flag_nl.svg 26 | flag_sl.svg 27 | 28 | 29 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: anymeal 2 | Section: utils 3 | Priority: optional 4 | Maintainer: Jan Wedekind 5 | Standards-Version: 4.7.0 6 | Vcs-Git: https://github.com/wedesoft/anymeal.git 7 | Vcs-Browser: https://github.com/wedesoft/anymeal 8 | Homepage: https://wedesoft.github.io/anymeal/ 9 | Build-Depends: debhelper-compat (=13), flex, googletest, libsqlite3-dev, qt6-base-dev-tools, qt6-tools-dev, qt6-base-dev, qt6-svg-dev, pkgconf 10 | Rules-Requires-Root: no 11 | 12 | Package: anymeal 13 | Architecture: any 14 | Depends: ${shlibs:Depends}, ${misc:Depends}, libqt6svg6, libqt6svgwidgets6 15 | Description: Recipe management software 16 | AnyMeal is a free recipe management software developed using 17 | SQLite3 and Qt6. It can manage a cookbook with more than 18 | 250000 MealMaster recipes, thereby allowing to import, 19 | export, search, display, edit, and print them. 20 | -------------------------------------------------------------------------------- /anymeal/export.hh: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2023 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #pragma once 17 | #include 18 | #include "recipe.hh" 19 | 20 | 21 | std::string recipe_to_mealmaster(Recipe &recipe); 22 | -------------------------------------------------------------------------------- /anymeal/ingredient.cc: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2023 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #include "ingredient.hh" 17 | 18 | 19 | Ingredient::Ingredient(void): m_amount_integer(0), m_amount_numerator(0), m_amount_denominator(1), m_amount_float(0.0) 20 | { 21 | } 22 | -------------------------------------------------------------------------------- /tests/suite.cc: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2021, 2023 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #include 17 | 18 | 19 | using namespace testing; 20 | 21 | int main(int argc, char *argv[]) { 22 | InitGoogleTest(&argc, argv); 23 | return RUN_ALL_TESTS(); 24 | } 25 | -------------------------------------------------------------------------------- /anymeal/partition.hh: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2023 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #pragma once 17 | #include 18 | #include 19 | #include 20 | 21 | 22 | std::vector recipes(std::istream &stream, bool *unexpected_eof=nullptr); 23 | -------------------------------------------------------------------------------- /Makefile.appimage: -------------------------------------------------------------------------------- 1 | # docker run -ti --rm -v `pwd`:/mnt -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix --privileged debian:buster /bin/bash 2 | # apt-get update 3 | # apt-get install build-essential flex libgtest-dev libsqlite3-dev qt6-default qttools6-dev-tools wget fuse file git 4 | # cd /mnt 5 | # ./configure --prefix=/usr 6 | # make clean 7 | # make 8 | # make check 9 | # make -f Makefile.appimage 10 | 11 | 12 | appimage: linuxdeploy-x86_64.AppImage linuxdeploy-plugin-qt-x86_64.AppImage 13 | rm -Rf AppDir 14 | $(MAKE) install DESTDIR=$(CURDIR)/AppDir 15 | PATH=/usr/lib/qt6/bin:/usr/lib/qt6/libexec:$(PATH) ./linuxdeploy-x86_64.AppImage --appdir AppDir --plugin qt --output appimage 16 | 17 | linuxdeploy-x86_64.AppImage: 18 | wget -q https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage 19 | chmod a+x $@ 20 | 21 | linuxdeploy-plugin-qt-x86_64.AppImage: 22 | wget -q https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage 23 | chmod a+x $@ 24 | -------------------------------------------------------------------------------- /anymeal/export_dialog.hh: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2023 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #pragma once 17 | #include 18 | #include "ui_export_dialog.hh" 19 | 20 | 21 | class ExportDialog: public QDialog 22 | { 23 | Q_OBJECT 24 | public: 25 | ExportDialog(QWidget *parent=NULL); 26 | std::string encoding(void); 27 | std::string error_file(void); 28 | Ui::ExportDialog m_ui; 29 | public slots: 30 | void select_error_file(void); 31 | }; 32 | -------------------------------------------------------------------------------- /anymeal/import_dialog.hh: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2023 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #pragma once 17 | #include 18 | #include 19 | #include "ui_import_dialog.hh" 20 | 21 | 22 | class ImportDialog: public QDialog 23 | { 24 | Q_OBJECT 25 | public: 26 | ImportDialog(QWidget *parent=NULL); 27 | std::string encoding(void); 28 | std::string error_file(void); 29 | Ui::ImportDialog m_ui; 30 | public slots: 31 | void select_error_file(void); 32 | }; 33 | -------------------------------------------------------------------------------- /tests/test_ingredient.cc: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2021, 2023 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #include 17 | #include "ingredient.hh" 18 | 19 | 20 | using namespace testing; 21 | using namespace std; 22 | 23 | 24 | TEST(IngredientTest, DefaultValues) { 25 | Ingredient ingredient; 26 | EXPECT_EQ(0, ingredient.amount_integer()); 27 | EXPECT_EQ(0, ingredient.amount_numerator()); 28 | EXPECT_EQ(1, ingredient.amount_denominator()); 29 | EXPECT_EQ(0.0, ingredient.amount_float()); 30 | } 31 | -------------------------------------------------------------------------------- /Dockerfile.sid: -------------------------------------------------------------------------------- 1 | # Docker file to build AnyMeal package for Debian Sid. 2 | # 3 | # configure /etc/default/docker 4 | # DOCKER_OPTS="--dns 8.8.8.8 --dns 8.8.4.4 --ip-masq=true" 5 | FROM debian:sid 6 | LABEL maintainer="Jan Wedekind " 7 | RUN echo "deb http://httpredir.debian.org/debian unstable main" > /etc/apt/sources.list 8 | RUN apt-get update # Forced update So 7. Nov 20:18:00 GMT 2021 9 | RUN apt-get -q -y dist-upgrade 10 | RUN apt-get install -q -y apt-utils 11 | RUN apt-get install -q -y build-essential 12 | RUN apt-get install -q -y devscripts equivs 13 | RUN apt-get install -q -y flex 14 | RUN apt-get install -q -y googletest 15 | RUN apt-get install -q -y libsqlite3-dev 16 | RUN apt-get install -q -y qt6-base-dev-tools 17 | RUN apt-get install -q -y qt6-tools-dev-tools 18 | RUN apt-get install -q -y qt6-base-dev 19 | 20 | RUN mkdir -p /usr/src/anymeal 21 | WORKDIR /usr/src/anymeal 22 | ADD debian/control debian/control 23 | RUN mk-build-deps --install --remove --tool 'apt-get -q --yes' debian/control 24 | COPY anymeal.tar.xz . 25 | COPY anymeal.tar.xz.asc . 26 | ADD configure.ac . 27 | ADD debian debian 28 | ADD Makefile.package . 29 | RUN make -f Makefile.package 30 | RUN dpkg --install pkg/anymeal_*.deb 31 | -------------------------------------------------------------------------------- /tests/Makefile.am: -------------------------------------------------------------------------------- 1 | SUFFIXES = .cc .hh 2 | 3 | SUBDIRS = fixtures 4 | 5 | if ENABLE_TESTS 6 | if GOOGLE_TEST_SRC 7 | BUILT_SOURCES = gtest-all.cc 8 | endif 9 | check_PROGRAMS = suite 10 | suite_LDFLAGS = 11 | if GOOGLE_TEST_SRC 12 | suite_SOURCES = suite.cc gtest-all.cc test_partition.cc test_recipe.cc test_ingredient.cc test_mealmaster.cc \ 13 | test_recode.cc test_database.cc test_html.cc test_export.cc 14 | suite_CXXFLAGS = -I$(top_srcdir)/anymeal $(SQLITE3_CFLAGS) -I$(GTESTSRC)/include -I$(GTESTSRC) 15 | suite_LDADD = ../anymeal/libanymeal.a $(SQLITE3_LDFLAGS) -lpthread 16 | else 17 | suite_SOURCES = suite.cc test_partition.cc test_recipe.cc test_ingredient.cc test_mealmaster.cc \ 18 | test_recode.cc test_database.cc test_html.cc test_export.cc 19 | suite_CXXFLAGS = -I$(top_srcdir)/anymeal $(SQLITE3_CFLAGS) $(GTEST_CFLAGS) 20 | suite_LDADD = ../anymeal/libanymeal.a $(GTEST_LIBS) $(SQLITE3_LDFLAGS) -lpthread 21 | endif 22 | else 23 | BUILT_SOURCES = 24 | check_PROGRAMS = 25 | endif 26 | 27 | CLEANFILES = $(BUILT_SOURCES) 28 | 29 | if GOOGLE_TEST_SRC 30 | gtest-all.cc: $(GTESTSRC)/src/gtest-all.cc 31 | rm -f $@ 32 | $(LN_S) $< $@ 33 | endif 34 | 35 | if ENABLE_TESTS 36 | check-local: 37 | ./suite 38 | endif 39 | -------------------------------------------------------------------------------- /anymeal/mealmaster.hh: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2023 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #pragma once 17 | #include 18 | #include 19 | #include 20 | #include "recipe.hh" 21 | 22 | 23 | class parse_exception: public std::exception 24 | { 25 | public: 26 | parse_exception(const std::string &error): m_error(error) {} 27 | virtual ~parse_exception(void) throw() {} 28 | virtual const char *what(void) const throw() { return m_error.c_str(); } 29 | protected: 30 | std::string m_error; 31 | }; 32 | 33 | Recipe parse_mealmaster(std::istream &stream); 34 | -------------------------------------------------------------------------------- /anymeal/category_dialog.hh: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2023 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #pragma once 17 | #include 18 | #include 19 | #include 20 | #include "ui_category_dialog.hh" 21 | #include "categories_model.hh" 22 | 23 | 24 | class CategoryDialog: public QDialog 25 | { 26 | Q_OBJECT 27 | public: 28 | CategoryDialog(QWidget *parent=NULL); 29 | void set_categories_model(CategoriesModel *categories_model); 30 | std::string category(void); 31 | protected: 32 | Ui::CategoryDialog m_ui; 33 | QCompleter *m_categories_completer; 34 | }; 35 | -------------------------------------------------------------------------------- /anymeal/add_dialog.hh: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2025 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #pragma once 17 | #include 18 | #include 19 | #include "ui_add_dialog.hh" 20 | #include "category_table_model.hh" 21 | 22 | class AddDialog: public QDialog 23 | { 24 | Q_OBJECT 25 | public: 26 | AddDialog(QWidget *parent=NULL); 27 | void set_model(CategoryTableModel *model) { m_model = model; } 28 | std::string name(void); 29 | public slots: 30 | void target_changed(const QString &target); 31 | protected: 32 | Ui::AddDialog m_ui; 33 | CategoryTableModel *m_model; 34 | QValidator *m_category_validator; 35 | }; 36 | -------------------------------------------------------------------------------- /anymeal/de.wedesoft.anymeal.appdata.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | de.wedesoft.anymeal 4 | CC0-1.0 5 | GPL-3.0+ 6 | AnyMeal recipe management software 7 | Manage a large collection of MealMaster recipes 8 | 9 |

10 | AnyMeal is a free recipe management software developed using 11 | SQLite3 and Qt6. It can manage a cookbook with more than 12 | 250000 MealMaster recipes, thereby allowing to import, 13 | export, search, display, edit, and print them. 14 |

15 |
16 | de.wedesoft.anymeal.desktop 17 | 18 | 19 | https://wedesoft.github.io/anymeal/anymeal.png 20 | Searching recipes by title, category, and ingredient 21 | 22 | 23 | https://wedesoft.github.io/anymeal/ 24 | 25 | anymeal 26 | 27 | jan@wedesoft.de 28 |
29 | -------------------------------------------------------------------------------- /anymeal/anymeal.cc: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2025 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #include 17 | #include 18 | #include "main_window.hh" 19 | 20 | 21 | int main(int argc, char *argv[]) { 22 | QCoreApplication::setApplicationName("anymeal"); 23 | QCoreApplication::addLibraryPath("."); 24 | QApplication app(argc, argv); 25 | QPixmap pixmap(":/images/splash.png"); 26 | QSplashScreen splash(pixmap); 27 | splash.show(); 28 | app.processEvents(); 29 | setlocale(LC_NUMERIC, "C"); // Change back behaviour of atof. 30 | MainWindow main_window; 31 | splash.finish(&main_window); 32 | main_window.show(); 33 | return app.exec(); 34 | } 35 | -------------------------------------------------------------------------------- /tests/fixtures/Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = header.mmf header2.mmf ingredient.mmf preparation.mmf fraction.mmf float.mmf mixed.mmf noamount.mmf continuation.mmf \ 2 | two_ingredients.mmf instructions1.mmf instructions2.mmf instructions3.mmf instructions4.mmf instructions5.mmf \ 3 | instructions6.mmf instructions7.mmf instructions8.mmf instructions9.mmf instructions10.mmf two_instructions.mmf \ 4 | no_servings.mmf ingredient_section.mmf section_hyphen.mmf section_spaces.mmf instruction_section.mmf \ 5 | ignore_newlines.mmf append_to_line.mmf stray_ingredient.mmf instruction_header.mmf skip_leading_spaces.mmf \ 6 | force_newline.mmf ignore_whitespaces.mmf instruction_number.mmf float_crlf.mmf instruction_eol.mmf \ 7 | instruction_eol2.mmf instruction_eol3.mmf instruction_eol4.mmf no_ingredient.mmf two_columns.mmf column_major.mmf \ 8 | three_ingredients.mmf flush_ingredients.mmf two_column_section.mmf overlong_ingredient.mmf overlong_ingredient2.mmf \ 9 | two_column_continuation.mmf two_column_continuation2.mmf two_column_continuation3.mmf two_column_continuation4.mmf \ 10 | two_column_trailing.mmf continuation_whitespace.mmf empty_ingredient_section.mmf section_whitespace.mmf \ 11 | erroneous_continuation.mmf discard_two_spaces.mmf ingredient_like.mmf title_spaces.mmf serving_spaces.mmf \ 12 | ignore_0x14.mmf replace_0x9.mmf unexpected_continuation.mmf 13 | -------------------------------------------------------------------------------- /anymeal/rename_dialog.hh: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2025 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #pragma once 17 | #include 18 | #include 19 | #include "ui_rename_dialog.hh" 20 | #include "category_table_model.hh" 21 | 22 | class RenameDialog: public QDialog 23 | { 24 | Q_OBJECT 25 | public: 26 | RenameDialog(QWidget *parent=NULL); 27 | void set_model(CategoryTableModel *model) { m_model = model; } 28 | void set_name(const std::string &name); 29 | std::string name(void); 30 | public slots: 31 | void target_changed(const QString &target); 32 | protected: 33 | Ui::RenameDialog m_ui; 34 | CategoryTableModel *m_model; 35 | QValidator *m_category_validator; 36 | }; 37 | -------------------------------------------------------------------------------- /anymeal/recipe.cc: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2023 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #include 17 | #include "recipe.hh" 18 | 19 | 20 | using namespace std; 21 | 22 | void Recipe::add_ingredient_section(int row, const char *title) { 23 | m_ingredient_sections.push_back(pair(row, title)); 24 | } 25 | 26 | void Recipe::add_instruction_section(int row, const char *title) { 27 | m_instruction_sections.push_back(pair(row, title)); 28 | } 29 | 30 | void Recipe::append_instruction(const char *instruction) { 31 | int n = m_instructions.size(); 32 | assert(n > 0); 33 | if (!m_instructions[n - 1].empty()) 34 | m_instructions[n - 1] += " "; 35 | m_instructions[n - 1] += instruction; 36 | } 37 | -------------------------------------------------------------------------------- /snapcraft.yaml: -------------------------------------------------------------------------------- 1 | name: anymeal 2 | base: core24 3 | version: '1.34' 4 | summary: recipe management software 5 | icon: anymeal/anymeal.png 6 | description: | 7 | AnyMeal is a free and open source recipe management software developed using SQLite3, Qt6, flex, libiconv, NSIS, and Googletest. 8 | It can manage a cookbook with more than 250,000 MealMaster recipes, thereby allowing to import, export, search, display, edit, 9 | and print them. AnyMeal is available for GNU/Linux and Microsoft Windows. 10 | 11 | confinement: strict 12 | 13 | parts: 14 | anymeal: 15 | plugin: autotools 16 | autotools-configure-parameters: ["--prefix=/usr"] 17 | source: https://github.com/wedesoft/anymeal.git 18 | build-packages: 19 | - flex 20 | - libsqlite3-dev 21 | - qt6-base-dev-tools 22 | - qt6-tools-dev 23 | - qt6-base-dev 24 | - qt6-svg-dev 25 | - pkgconf 26 | stage-packages: 27 | - libqt6gui6 28 | - libqt6svg6 29 | - libqt6svgwidgets6 30 | - libqt6printsupport6 31 | 32 | apps: 33 | anymeal: 34 | command: usr/bin/anymeal 35 | plugs: 36 | - desktop 37 | - desktop-legacy 38 | - x11 39 | - unity7 40 | - wayland 41 | - home 42 | environment: 43 | QT_PLUGIN_PATH: ${SNAP}/usr/lib/${CRAFT_ARCH_TRIPLET_BUILD_FOR}/qt6/plugins/ 44 | QT_QPA_PLATFORM_PLUGIN_PATH: ${SNAP}/usr/lib/${CRAFT_ARCH_TRIPLET_BUILD_FOR}/qt6/plugins/platforms/ 45 | -------------------------------------------------------------------------------- /anymeal/category_picker.hh: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2025 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #pragma once 17 | #include 18 | #include 19 | #include "category_table_model.hh" 20 | #include "ui_category_picker.hh" 21 | 22 | class CategoryPicker: public QDialog 23 | { 24 | Q_OBJECT 25 | public: 26 | CategoryPicker(QWidget *parent=NULL); 27 | void set_model(CategoryTableModel *model); 28 | Ui::CategoryPicker m_ui; 29 | public slots: 30 | void add_category(void); 31 | void delete_categories(void); 32 | void rename_category(void); 33 | void merge_category(void); 34 | protected: 35 | QSortFilterProxyModel m_sort_filter_proxy_model; 36 | CategoryTableModel *m_model; 37 | }; 38 | -------------------------------------------------------------------------------- /anymeal/categories_model.hh: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2023 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #pragma once 17 | #include 18 | #include 19 | #include 20 | #include "database.hh" 21 | 22 | 23 | class CategoriesModel: public QAbstractListModel 24 | { 25 | Q_OBJECT 26 | public: 27 | CategoriesModel(QObject *parent, Database *database); 28 | void reset(void); 29 | virtual int rowCount(const QModelIndex &parent=QModelIndex()) const; 30 | virtual QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const; 31 | std::vector categories(void) { return m_categories; }; 32 | protected: 33 | Database *m_database; 34 | std::vector m_categories; 35 | }; 36 | -------------------------------------------------------------------------------- /anymeal/merge_dialog.hh: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2025 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #pragma once 17 | #include 18 | #include 19 | #include "ui_merge_dialog.hh" 20 | #include "category_table_model.hh" 21 | 22 | class MergeDialog: public QDialog 23 | { 24 | Q_OBJECT 25 | public: 26 | MergeDialog(QWidget *parent=NULL); 27 | void set_model(CategoryTableModel *model) { m_model = model; } 28 | void set_name(const std::string &name); 29 | std::string name(void); 30 | public slots: 31 | void target_changed(const QString &target); 32 | protected: 33 | Ui::MergeDialog m_ui; 34 | std::string m_name; 35 | CategoryTableModel *m_model; 36 | QValidator *m_category_validator; 37 | }; 38 | -------------------------------------------------------------------------------- /anymeal/category_dialog.cc: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2023 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #include "category_dialog.hh" 17 | 18 | 19 | using namespace std; 20 | 21 | CategoryDialog::CategoryDialog(QWidget *parent): 22 | QDialog(parent), m_categories_completer(NULL) 23 | { 24 | m_ui.setupUi(this); 25 | } 26 | 27 | void CategoryDialog::set_categories_model(CategoriesModel *categories_model) { 28 | if (m_categories_completer) { 29 | delete m_categories_completer; 30 | m_categories_completer = NULL; 31 | }; 32 | m_categories_completer = new QCompleter(categories_model, this); 33 | m_ui.category_edit->setCompleter(m_categories_completer); 34 | } 35 | 36 | string CategoryDialog::category(void) { 37 | return m_ui.category_edit->text().toUtf8().constData(); 38 | } 39 | -------------------------------------------------------------------------------- /anymeal/html.hh: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2025 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #pragma once 17 | #include 18 | #include 19 | #include "recipe.hh" 20 | 21 | 22 | #define UNITS 32 23 | 24 | std::string notrans(const char *context, const char *text); 25 | 26 | std::string html_amount(Ingredient &ingredient); 27 | 28 | std::string html_unit(const std::string &unit, std::string (*translate)(const char *, const char *)); 29 | 30 | int index_of_unit(const std::string &unit); 31 | 32 | const char *unit_from_index(int index); 33 | 34 | std::string recipe_to_html(Recipe &recipe, std::string (*translate)(const char *, const char *)=¬rans); 35 | 36 | std::string recipes_to_html(std::vector &recipes, std::string (*translate)(const char *, const char *)=¬rans); 37 | -------------------------------------------------------------------------------- /tests/test_recipe.cc: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2021, 2023 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #include 17 | #include "recipe.hh" 18 | 19 | 20 | using namespace testing; 21 | using namespace std; 22 | 23 | 24 | TEST(RecipeTest, DefaultValues) { 25 | EXPECT_EQ(0, Recipe().servings()); 26 | } 27 | 28 | TEST(RecipeTest, AppendInstruction) { 29 | Recipe recipe; 30 | recipe.add_instruction("test"); 31 | recipe.append_instruction("other"); 32 | ASSERT_EQ(1, recipe.instructions().size()); 33 | EXPECT_EQ("test other", recipe.instructions()[0]); 34 | } 35 | 36 | TEST(RecipeTest, AppendToEmptyInstruction) { 37 | Recipe recipe; 38 | recipe.add_instruction(""); 39 | recipe.append_instruction("other"); 40 | ASSERT_EQ(1, recipe.instructions().size()); 41 | EXPECT_EQ("other", recipe.instructions()[0]); 42 | } 43 | -------------------------------------------------------------------------------- /anymeal/converter_window.hh: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2023 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #pragma once 17 | #include 18 | #include 19 | #include "ui_converter_window.hh" 20 | 21 | 22 | #define INGREDIENTS 24 23 | #define CUSTOM 23 24 | 25 | typedef enum { WEIGHT = 0, VOLUME = 1 } UnitType; 26 | 27 | class ConverterWindow: public QDialog 28 | { 29 | Q_OBJECT 30 | public: 31 | ConverterWindow(QWidget *parent=NULL); 32 | static std::string translate(const char *context, const char *text); 33 | static double conversion_factor(int unit_index); 34 | static UnitType unit_type(int unit_index); 35 | QString ingredient(int index); 36 | double density(int index); 37 | Ui::ConverterWindow m_ui; 38 | public slots: 39 | void update_value(void); 40 | void change_ingredient(int index); 41 | }; 42 | -------------------------------------------------------------------------------- /anymeal/anymeal.man: -------------------------------------------------------------------------------- 1 | .\" Hey, EMACS: -*- nroff -*- 2 | .\" First parameter, NAME, should be all caps 3 | .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection 4 | .\" other parameters are allowed: see man(7), man(1) 5 | .TH ANYMEAL 1 "February 23, 2024" 6 | .\" Please adjust this date whenever revising the manpage. 7 | .\" 8 | .\" Some roff macros, for reference: 9 | .\" .nh disable hyphenation 10 | .\" .hy enable hyphenation 11 | .\" .ad l left justify 12 | .\" .ad b justify to both left and right margins 13 | .\" .nf disable filling 14 | .\" .fi enable filling 15 | .\" .br insert line break 16 | .\" .sp insert n+1 empty lines 17 | .\" for manpage-specific macros, see man(7) 18 | .SH NAME 19 | anymeal \- recipe management software 20 | .SH SYNOPSIS 21 | .B anymeal 22 | .SH DESCRIPTION 23 | .\" TeX users may be more comfortable with the \fB\fP and 24 | .\" \fI\fP escape sequences to invode bold face and italics, 25 | .\" respectively. 26 | \fBanymeal\fP is a free recipe management software developed using SQLite3 and Qt6. It can manage a cookbook with more than 250,000 MealMaster recipes, thereby allowing to import, export, search, display, edit, and print them. 27 | The recipe database file is located at $HOME/.local/share/anymeal/anymeal.sqlite . 28 | .SH AUTHOR 29 | anymeal was written by Jan Wedekind . 30 | .PP 31 | This manual page was written by Sandro Tosi , 32 | for the Debian project (but may be used by others). 33 | -------------------------------------------------------------------------------- /anymeal/categories_model.cc: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2023 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #include "categories_model.hh" 17 | 18 | 19 | CategoriesModel::CategoriesModel(QObject *parent, Database *database): QAbstractListModel(parent), m_database(database) { 20 | m_categories = m_database->categories(); 21 | } 22 | 23 | void CategoriesModel::reset(void) { 24 | beginResetModel(); 25 | m_categories = m_database->categories(); 26 | endResetModel(); 27 | } 28 | 29 | int CategoriesModel::rowCount(const QModelIndex &) const { 30 | return m_categories.size(); 31 | } 32 | 33 | QVariant CategoriesModel::data(const QModelIndex &index, int role) const { 34 | QVariant result; 35 | if (role == Qt::DisplayRole || role == Qt::EditRole) { 36 | int row = index.row(); 37 | result = QString(m_categories[row].c_str()); 38 | }; 39 | return result; 40 | } 41 | -------------------------------------------------------------------------------- /anymeal/add_dialog.cc: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2025 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #include "add_dialog.hh" 17 | 18 | using namespace std; 19 | 20 | AddDialog::AddDialog(QWidget *parent): 21 | QDialog(parent), m_model(NULL), m_category_validator(NULL) 22 | { 23 | m_ui.setupUi(this); 24 | connect(m_ui.add_edit, &QLineEdit::textChanged, this, &AddDialog::target_changed); 25 | m_category_validator = new QRegularExpressionValidator(QRegularExpression("[^,]*"), this); 26 | m_ui.add_edit->setValidator(m_category_validator); 27 | } 28 | 29 | string AddDialog::name(void) { 30 | return m_ui.add_edit->text().toUtf8().constData(); 31 | } 32 | 33 | void AddDialog::target_changed(const QString &target) { 34 | const char *target_str = target.toUtf8().constData(); 35 | bool exist = m_model->get_category_id(target_str); 36 | m_ui.button_box->setEnabled(!exist); 37 | } 38 | -------------------------------------------------------------------------------- /anymeal/titles_model.hh: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2023 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #pragma once 17 | #include 18 | #include 19 | #include 20 | #include "database.hh" 21 | 22 | 23 | class TitlesModel: public QAbstractListModel 24 | { 25 | Q_OBJECT 26 | public: 27 | TitlesModel(QObject *parent, Database *database); 28 | void reset(void); 29 | virtual int rowCount(const QModelIndex &parent=QModelIndex()) const; 30 | virtual QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const; 31 | sqlite3_int64 recipeid(const QModelIndex &index); 32 | QModelIndex edit_entry(const QModelIndex &index, sqlite3_int64 id, const char *title); 33 | QModelIndex add_entry(sqlite3_int64 id, const char *title); 34 | protected: 35 | Database *m_database; 36 | std::vector > m_titles; 37 | }; 38 | -------------------------------------------------------------------------------- /anymeal/recode.hh: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2025 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #pragma once 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "ingredient.hh" 22 | #include "recipe.hh" 23 | 24 | 25 | class recode_exception: public std::exception 26 | { 27 | public: 28 | recode_exception(const std::string &error): m_error(error) {} 29 | virtual ~recode_exception(void) throw() {} 30 | virtual const char *what(void) const throw() { return m_error.c_str(); } 31 | protected: 32 | std::string m_error; 33 | }; 34 | 35 | class Recoder 36 | { 37 | public: 38 | Recoder(const char *fromcode, const char *tocode); 39 | virtual ~Recoder(void); 40 | std::string process(const std::string &text); 41 | Ingredient process_ingredient(Ingredient &ingredient); 42 | Recipe process_recipe(Recipe &recipe); 43 | protected: 44 | iconv_t m_request; 45 | }; 46 | -------------------------------------------------------------------------------- /anymeal/partition.cc: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2023 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #include 17 | #include "partition.hh" 18 | 19 | 20 | using namespace std; 21 | 22 | vector recipes(istream &stream, bool *unexpected_eof) { 23 | vector result; 24 | ostringstream recipe; 25 | string line; 26 | bool on = false; 27 | while (getline(stream, line)) { 28 | if (!line.empty() && *line.rbegin() == '\r') 29 | line.erase(line.length() - 1, 1); 30 | if ((line.rfind("MMMMM", 0) == 0 || line.rfind("-----", 0) == 0) && line.length() > 5) 31 | on = true; 32 | if (on) 33 | recipe << line << "\r\n"; 34 | if (line == "MMMMM" || line == "-----") { 35 | result.push_back(recipe.str()); 36 | recipe.str(""); 37 | recipe.clear(); 38 | on = false; 39 | }; 40 | }; 41 | if (unexpected_eof) 42 | *unexpected_eof = on; 43 | return result; 44 | } 45 | -------------------------------------------------------------------------------- /anymeal/flag_sl.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /anymeal/rename_dialog.cc: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2025 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #include "rename_dialog.hh" 17 | 18 | using namespace std; 19 | 20 | RenameDialog::RenameDialog(QWidget *parent): 21 | QDialog(parent), m_model(NULL), m_category_validator(NULL) 22 | { 23 | m_ui.setupUi(this); 24 | connect(m_ui.rename_edit, &QLineEdit::textChanged, this, &RenameDialog::target_changed); 25 | m_category_validator = new QRegularExpressionValidator(QRegularExpression("[^,]*"), this); 26 | m_ui.rename_edit->setValidator(m_category_validator); 27 | } 28 | 29 | void RenameDialog::set_name(const string &name) { 30 | m_ui.rename_edit->setText(name.c_str()); 31 | } 32 | 33 | string RenameDialog::name(void) { 34 | return m_ui.rename_edit->text().toUtf8().constData(); 35 | } 36 | 37 | void RenameDialog::target_changed(const QString &target) { 38 | m_ui.button_box->setEnabled(m_model->get_category_id(target.toUtf8().constData()) == 0); 39 | } 40 | -------------------------------------------------------------------------------- /Makefile.sid: -------------------------------------------------------------------------------- 1 | # make -f Makefile.sid clean all 2 | CODENAME=sid 3 | BASEIMAGE=debian:$(CODENAME) 4 | IMAGE=wedesoft/anymeal-$(BASEIMAGE) 5 | VERSION=$(shell grep AC_INIT configure.ac | sed -e "s/.*\[\([0-9\.]*\)\].*/\1/") 6 | PACKAGE=anymeal_$(shell dpkg-parsechangelog --show-field Version) 7 | 8 | all: dput 9 | 10 | dput: sign 11 | cd pkg && dput -f mentors $(PACKAGE)_amd64.changes && cd .. 12 | 13 | report: 14 | uscan --force-download 15 | 16 | sign: package 17 | cd pkg && debsign -k $(GPGKEY) $(PACKAGE)_amd64.changes && cd .. 18 | 19 | # "mentors" needs to be defined in ~/.dput.cf (see https://mentors.debian.net/intro-maintainers and etc/dput.cf) 20 | detach-sig: anymeal-$(VERSION).tar.xz.asc 21 | 22 | package: pkg/$(PACKAGE).dsc 23 | 24 | pkg/$(PACKAGE).dsc: container 25 | docker run $(IMAGE) tar c pkg | tar x 26 | 27 | container: docker docker/Dockerfile docker/anymeal.tar.xz docker/anymeal.tar.xz.asc \ 28 | docker/debian docker/configure.ac docker/Makefile.package 29 | cd docker && docker build -t $(IMAGE) --progress=plain . && cd .. 30 | 31 | docker: 32 | mkdir -p $@ 33 | 34 | docker/Dockerfile: Dockerfile.sid 35 | cp $< $@ 36 | 37 | docker/anymeal.tar.xz: anymeal-$(VERSION).tar.xz 38 | cp $< $@ 39 | 40 | docker/anymeal.tar.xz.asc: anymeal-$(VERSION).tar.xz.asc 41 | cp $< $@ 42 | 43 | docker/debian:: debian 44 | cp -a $< docker 45 | 46 | docker/configure.ac: configure.ac 47 | cp $< $@ 48 | 49 | docker/Makefile.package: Makefile.package 50 | cp $< $@ 51 | 52 | anymeal-$(VERSION).tar.xz: 53 | make dist-xz 54 | 55 | anymeal-$(VERSION).tar.xz.asc: anymeal-$(VERSION).tar.xz 56 | gpg --armor --output $@ --detach-sig $< 57 | 58 | clean: 59 | rm -Rf anymeal-$(VERSION).tar.xz docker pkg 60 | -------------------------------------------------------------------------------- /anymeal/merge_dialog.cc: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2025 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #include "merge_dialog.hh" 17 | 18 | using namespace std; 19 | 20 | MergeDialog::MergeDialog(QWidget *parent): 21 | QDialog(parent), m_model(NULL), m_category_validator(NULL) 22 | { 23 | m_ui.setupUi(this); 24 | connect(m_ui.merge_edit, &QLineEdit::textChanged, this, &MergeDialog::target_changed); 25 | m_category_validator = new QRegularExpressionValidator(QRegularExpression("[^,]*"), this); 26 | m_ui.merge_edit->setValidator(m_category_validator); 27 | } 28 | 29 | void MergeDialog::set_name(const string &name) { 30 | m_name = name; 31 | m_ui.merge_edit->setText(name.c_str()); 32 | } 33 | 34 | string MergeDialog::name(void) { 35 | return m_ui.merge_edit->text().toUtf8().constData(); 36 | } 37 | 38 | void MergeDialog::target_changed(const QString &target) { 39 | const char *target_str = target.toUtf8().constData(); 40 | bool equal = m_name == target_str; 41 | bool exist = m_model->get_category_id(target_str); 42 | m_ui.button_box->setEnabled(!equal && exist); 43 | } 44 | -------------------------------------------------------------------------------- /anymeal/export_dialog.cc: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2025 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #include 17 | #include 18 | #include "export_dialog.hh" 19 | 20 | 21 | using namespace std; 22 | 23 | ExportDialog::ExportDialog(QWidget *parent): 24 | QDialog(parent) 25 | { 26 | m_ui.setupUi(this); 27 | connect(m_ui.browse_button, &QPushButton::clicked, this, &ExportDialog::select_error_file); 28 | QDir dir = QDir(QStandardPaths::writableLocation(QStandardPaths::TempLocation)); 29 | m_ui.error_file_edit->setText(dir.filePath("export-errors.mmf")); 30 | } 31 | 32 | string ExportDialog::encoding(void) { 33 | return m_ui.encoding_combo->currentText().toUtf8().constData(); 34 | } 35 | 36 | string ExportDialog::error_file(void) { 37 | return m_ui.error_file_edit->text().toUtf8().constData(); 38 | } 39 | 40 | void ExportDialog::select_error_file(void) { 41 | QString result = QFileDialog::getSaveFileName(this, tr("Select Error File"), "", tr("MealMaster (*.mm *.MM *.mmf *.MMF);;" 42 | "Text (*.txt *.TXT);;All files (*)")); 43 | if (!result.isEmpty()) { 44 | m_ui.error_file_edit->setText(result); 45 | }; 46 | } 47 | -------------------------------------------------------------------------------- /anymeal/import_dialog.cc: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2025 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #include 17 | #include 18 | #include "import_dialog.hh" 19 | 20 | 21 | using namespace std; 22 | 23 | ImportDialog::ImportDialog(QWidget *parent): 24 | QDialog(parent) 25 | { 26 | m_ui.setupUi(this); 27 | connect(m_ui.browse_button, &QPushButton::clicked, this, &ImportDialog::select_error_file); 28 | QString path = QStandardPaths::writableLocation(QStandardPaths::TempLocation); 29 | QDir dir(path); 30 | m_ui.error_file_edit->setText(dir.filePath("import-errors.mmf")); 31 | } 32 | 33 | string ImportDialog::encoding(void) { 34 | return m_ui.encoding_combo->currentText().toUtf8().constData(); 35 | } 36 | 37 | string ImportDialog::error_file(void) { 38 | return m_ui.error_file_edit->text().toUtf8().constData(); 39 | } 40 | 41 | void ImportDialog::select_error_file(void) { 42 | QString result = QFileDialog::getSaveFileName(this, tr("Select Error File"), "", tr("MealMaster (*.mm *.MM *.mmf *.MMF);;" 43 | "Text (*.txt *.TXT);;All files (*)")); 44 | if (!result.isEmpty()) { 45 | m_ui.error_file_edit->setText(result); 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /anymeal/instructions_model.hh: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2023 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #pragma once 17 | #include 18 | #include 19 | #include 20 | #include "recipe.hh" 21 | 22 | 23 | class InstructionsModel: public QAbstractListModel 24 | { 25 | Q_OBJECT 26 | public: 27 | InstructionsModel(QObject *parent, std::vector &instructions, std::vector > §ions); 28 | virtual int rowCount(const QModelIndex &parent=QModelIndex()) const; 29 | virtual QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const; 30 | std::string get_section(const QModelIndex &index) const; 31 | void set_section(const QModelIndex &index, const char *text); 32 | QModelIndex add_section(const QModelIndex &idx); 33 | QModelIndex remove_section(const QModelIndex &idx); 34 | std::string get_text(const QModelIndex &index) const; 35 | void set_text(const QModelIndex &index, const char *text); 36 | std::vector get_instructions(void); 37 | std::vector > get_sections(void); 38 | bool has_acceptable_input(void); 39 | protected: 40 | std::vector m_instructions; 41 | std::vector m_sections; 42 | }; 43 | -------------------------------------------------------------------------------- /anymeal/ingredient.hh: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2023 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #pragma once 17 | #include 18 | 19 | 20 | class Ingredient 21 | { 22 | public: 23 | Ingredient(void); 24 | int amount_integer(void) { return m_amount_integer; } 25 | void set_amount_integer(int amount_integer) { m_amount_integer = amount_integer; } 26 | int amount_numerator(void) { return m_amount_numerator; } 27 | void set_amount_numerator(int amount_numerator) { m_amount_numerator = amount_numerator; } 28 | int amount_denominator(void) { return m_amount_denominator; } 29 | void set_amount_denominator(int amount_denominator) { m_amount_denominator = amount_denominator; } 30 | double amount_float(void) { return m_amount_float; } 31 | void set_amount_float(double amount_float) { m_amount_float = amount_float; } 32 | std::string &unit(void) { return m_unit; } 33 | const char *unit_c_str(void) { return m_unit.c_str(); } 34 | void set_unit(const char *unit) { m_unit = unit; } 35 | std::string &text(void) { return m_text; } 36 | const char *text_c_str(void) { return m_text.c_str(); } 37 | void add_text(const char *text) { m_text += text; } 38 | void set_text(const char *text) { m_text = text; } 39 | protected: 40 | int m_amount_integer; 41 | int m_amount_numerator; 42 | int m_amount_denominator; 43 | double m_amount_float; 44 | std::string m_unit; 45 | std::string m_text; 46 | }; 47 | -------------------------------------------------------------------------------- /anymeal/titles_model.cc: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2023 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #include "titles_model.hh" 17 | 18 | 19 | using namespace std; 20 | 21 | TitlesModel::TitlesModel(QObject *parent, Database *database): QAbstractListModel(parent), m_database(database) { 22 | m_titles = m_database->recipe_info(); 23 | } 24 | 25 | void TitlesModel::reset(void) { 26 | beginResetModel(); 27 | m_titles = m_database->recipe_info(); 28 | endResetModel(); 29 | } 30 | 31 | int TitlesModel::rowCount(const QModelIndex &) const { 32 | return m_titles.size(); 33 | } 34 | 35 | QVariant TitlesModel::data(const QModelIndex &index, int role) const { 36 | QVariant result; 37 | if (role == Qt::DisplayRole) { 38 | int row = index.row(); 39 | result = QString(m_titles[row].second.c_str()); 40 | }; 41 | return result; 42 | } 43 | 44 | sqlite_int64 TitlesModel::recipeid(const QModelIndex &index) { 45 | int row = index.row(); 46 | return m_titles[row].first; 47 | } 48 | 49 | QModelIndex TitlesModel::edit_entry(const QModelIndex &index, sqlite3_int64 id, const char *title) { 50 | int row = index.row(); 51 | m_titles[row] = pair(id, title); 52 | emit dataChanged(index, index); 53 | return index; 54 | } 55 | 56 | QModelIndex TitlesModel::add_entry(sqlite3_int64 id, const char *title) { 57 | int row = m_titles.size(); 58 | beginInsertRows(QModelIndex(), row, row); 59 | m_titles.push_back(pair(id, title)); 60 | endInsertRows(); 61 | return index(row); 62 | } 63 | -------------------------------------------------------------------------------- /anymeal/category_table_model.hh: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2025 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #pragma once 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "database.hh" 22 | 23 | 24 | class CategoryTableModel: public QAbstractTableModel 25 | { 26 | Q_OBJECT 27 | public: 28 | CategoryTableModel(QObject *parent, Database *database); 29 | int rowCount(const QModelIndex &parent=QModelIndex()) const; 30 | int columnCount(const QModelIndex &parent=QModelIndex()) const; 31 | QVariant headerData(int section, Qt::Orientation orientation, int role) const; 32 | QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const; 33 | bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); 34 | Qt::ItemFlags flags(const QModelIndex &index) const; 35 | void reset(const std::set &selection); 36 | std::set selection(void) { return m_selection; }; 37 | std::string category(int row) { return m_categories_and_counts[row].first; } 38 | QModelIndex add_category(const std::string &name); 39 | void delete_category(int row); 40 | void rename_category(int row, const std::string &name); 41 | void merge_category(int row, const std::string &name); 42 | sqlite3_int64 get_category_id(const char *name) { return m_database->get_category_id(name); } 43 | protected: 44 | Database *m_database; 45 | std::set m_selection; 46 | std::vector > m_categories_and_counts; 47 | }; 48 | -------------------------------------------------------------------------------- /anymeal/add_dialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | AddDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 431 10 | 92 11 | 12 | 13 | 14 | Add Category 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | &Add Category 23 | 24 | 25 | add_edit 26 | 27 | 28 | 29 | 30 | 31 | 32 | 40 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | Qt::Vertical 42 | 43 | 44 | 45 | 20 46 | 2 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | Qt::Horizontal 55 | 56 | 57 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | button_box 67 | accepted() 68 | AddDialog 69 | accept() 70 | 71 | 72 | 248 73 | 254 74 | 75 | 76 | 157 77 | 274 78 | 79 | 80 | 81 | 82 | button_box 83 | rejected() 84 | AddDialog 85 | reject() 86 | 87 | 88 | 316 89 | 260 90 | 91 | 92 | 286 93 | 274 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /anymeal/merge_dialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MergeDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 431 10 | 92 11 | 12 | 13 | 14 | Merge Category 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Merge Category Into: 23 | 24 | 25 | merge_edit 26 | 27 | 28 | 29 | 30 | 31 | 32 | 40 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | Qt::Vertical 42 | 43 | 44 | 45 | 20 46 | 2 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | Qt::Horizontal 55 | 56 | 57 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | button_box 67 | accepted() 68 | MergeDialog 69 | accept() 70 | 71 | 72 | 248 73 | 254 74 | 75 | 76 | 157 77 | 274 78 | 79 | 80 | 81 | 82 | button_box 83 | rejected() 84 | MergeDialog 85 | reject() 86 | 87 | 88 | 316 89 | 260 90 | 91 | 92 | 286 93 | 274 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /anymeal/rename_dialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | RenameDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 431 10 | 92 11 | 12 | 13 | 14 | Rename Category 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Rename Category To: 23 | 24 | 25 | rename_edit 26 | 27 | 28 | 29 | 30 | 31 | 32 | 40 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | Qt::Vertical 42 | 43 | 44 | 45 | 20 46 | 2 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | Qt::Horizontal 55 | 56 | 57 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | button_box 67 | accepted() 68 | RenameDialog 69 | accept() 70 | 71 | 72 | 248 73 | 254 74 | 75 | 76 | 157 77 | 274 78 | 79 | 80 | 81 | 82 | button_box 83 | rejected() 84 | RenameDialog 85 | reject() 86 | 87 | 88 | 316 89 | 260 90 | 91 | 92 | 286 93 | 274 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_PREREQ([2.69]) 2 | AC_INIT([anymeal], [1.34], [jan@wedesoft.de]) 3 | AC_CONFIG_AUX_DIR([.]) 4 | AM_INIT_AUTOMAKE([--warnings=no-portability foreign]) 5 | AC_CONFIG_MACRO_DIR([m4]) 6 | LT_INIT 7 | AC_PROG_CXX 8 | AC_PROG_INSTALL 9 | AC_LANG([C++]) 10 | AC_CHECK_TOOL([RANLIB],[ranlib],[:]) 11 | AC_PROG_LN_S 12 | PKG_PROG_PKG_CONFIG 13 | 14 | dnl Check for flex. 15 | AC_PROG_LEX([noyywrap]) 16 | if test "x$LEX" != xflex; then 17 | AC_MSG_ERROR([Could not find flex]) 18 | fi 19 | 20 | dnl Check for windres. 21 | AC_CHECK_PROG([WINDRES],windres,windres,no) 22 | AM_CONDITIONAL([HAVE_WINDRES], [test "x$WINDRES" = "xwindres"]) 23 | 24 | dnl Check for Googletest source file. 25 | AC_ARG_WITH([gtest], 26 | [AC_HELP_STRING([--with-gtest=],[directory of Google Test framework])], 27 | [GTESTSRC="$withval"], 28 | [GTESTSRC="/usr/src/googletest/googletest"]) 29 | AC_MSG_CHECKING([Google Test source code]) 30 | if test -e "$GTESTSRC/src/gtest-all.cc"; then 31 | AC_MSG_RESULT([found]) 32 | else 33 | AC_MSG_RESULT([not found]) 34 | fi 35 | AC_SUBST([GTESTSRC]) 36 | 37 | dnl Check for Googletest library. 38 | PKG_CHECK_MODULES([GTEST], [gtest >= 1.12.0], 39 | [GTESTLIB='yes'], 40 | [GTESTLIB='no']) 41 | AC_SUBST([GTEST_CFLAGS]) 42 | AC_SUBST([GTEST_LIBS]) 43 | 44 | dnl Enable unit tests if Googletest source or library was found. 45 | AM_CONDITIONAL([ENABLE_TESTS], [test -e "$GTESTSRC/src/gtest-all.cc" || test "x$GTESTLIB" = xyes]) 46 | AM_CONDITIONAL([GOOGLE_TEST_SRC], [test -e "$GTESTSRC/src/gtest-all.cc"]) 47 | 48 | dnl Check for iconv-library. 49 | AC_MSG_CHECKING([for iconv-library]) 50 | AC_TRY_LINK([#include 51 | #include 52 | #include 53 | #include ], 54 | [iconv_open("US-ASCII", "UTF-8")], 55 | [AC_MSG_RESULT([found])], 56 | [AC_MSG_ERROR([Check for iconv-library failed.])]); 57 | 58 | dnl Check for SQLite 3 library. 59 | AX_LIB_SQLITE3([3.6.19]) 60 | if test "x$SQLITE3_VERSION" = "x"; then 61 | AC_MSG_ERROR([Could not find SQLite 3 library]) 62 | fi 63 | 64 | dnl Check for Qt6 library. 65 | AX_HAVE_QT 66 | if test "x$have_qt" = "xno"; then 67 | AC_MSG_ERROR([Could not locate Qt6 installation]) 68 | fi 69 | 70 | AC_CONFIG_HEADERS([config.h]) 71 | AC_CHECK_HEADERS([cassert ios sstream fstream string]) 72 | AC_OUTPUT([Makefile 73 | anymeal/Makefile 74 | anymeal/locale/Makefile 75 | anymeal/locale/de/Makefile 76 | anymeal/locale/it/Makefile 77 | anymeal/locale/nl/Makefile 78 | anymeal/locale/fr/Makefile 79 | anymeal/locale/sl/Makefile 80 | tests/Makefile 81 | tests/fixtures/Makefile]) 82 | -------------------------------------------------------------------------------- /anymeal/edit_dialog.hh: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2023 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #pragma once 17 | #include 18 | #include 19 | #include "recipe.hh" 20 | #include "ingredient_model.hh" 21 | #include "instructions_model.hh" 22 | #include "category_table_model.hh" 23 | #include "converter_window.hh" 24 | #include "ui_edit_dialog.hh" 25 | 26 | 27 | class EditDialog: public QDialog 28 | { 29 | Q_OBJECT 30 | public: 31 | EditDialog(QWidget *parent=NULL); 32 | void set_recipe(Recipe &recipe); 33 | Recipe get_recipe(void); 34 | void set_category_table_model(CategoryTableModel *model) { m_category_table_model = model; } 35 | int fraction_str_length(void); 36 | std::string category_string(const std::set &categories); 37 | std::set categories(void); 38 | public slots: 39 | void select_categories(void); 40 | void select_ingredient(const QModelIndex ¤t, const QModelIndex &previous); 41 | void unit_changed(int idx); 42 | void ingredient_name_changed(const QString &text); 43 | void amount_type_changed(int value); 44 | void amount_int_changed(int value); 45 | void amount_float_changed(double value); 46 | void add_ingredient(void); 47 | void delete_ingredient(void); 48 | void ingredient_section_changed(const QString &text); 49 | void add_ingredient_section(void); 50 | void move_ingredient_up(void); 51 | void move_ingredient_down(void); 52 | void select_instruction(const QModelIndex ¤t, const QModelIndex &previous); 53 | void section_changed(const QString &text); 54 | void add_instruction_section(void); 55 | void remove_instruction_section(void); 56 | void instructions_text_changed(void); 57 | void update_ok_button(void); 58 | void unit_converter(void); 59 | protected: 60 | Ui::EditDialog m_ui; 61 | ConverterWindow m_converter_window; 62 | CategoryTableModel *m_category_table_model; 63 | IngredientModel *m_ingredient_model; 64 | InstructionsModel *m_instructions_model; 65 | QValidator *m_title_validator; 66 | QValidator *m_servings_unit_validator; 67 | }; 68 | -------------------------------------------------------------------------------- /anymeal/ingredient_model.hh: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2023 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #pragma once 17 | #include 18 | #include 19 | #include 20 | #include "ingredient.hh" 21 | 22 | 23 | class IngredientModel: public QAbstractItemModel 24 | { 25 | Q_OBJECT 26 | public: 27 | IngredientModel(QObject *parent, std::vector &ingredients, std::vector > §ions); 28 | static std::string translate(const char *context, const char *text); 29 | int columnCount(const QModelIndex &parent = QModelIndex()) const; 30 | QVariant headerData(int section, Qt::Orientation orientation, int role) const; 31 | int rowCount(const QModelIndex &parent = QModelIndex()) const; 32 | QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const; 33 | QModelIndex index(int row, int column, const QModelIndex &parent) const; 34 | QModelIndex parent(const QModelIndex &index) const; 35 | bool is_ingredient(const QModelIndex &index) const; 36 | int ingredient_index(const QModelIndex &index) const; 37 | Ingredient get_ingredient(const QModelIndex &index) const; 38 | void set_ingredient(const QModelIndex &index, Ingredient &ingredient); 39 | QModelIndex add_ingredient(const QModelIndex &idx, Ingredient &Ingredient); 40 | QModelIndex delete_ingredient(const QModelIndex &idx); 41 | std::string get_ingredient_section(const QModelIndex &index) const; 42 | void set_ingredient_section(const QModelIndex &index, const char *text); 43 | QModelIndex add_ingredient_section(const QModelIndex &idx, const char *text); 44 | void swap_neighbouring_sections(int row1, int row2); 45 | QModelIndex move_up(const QModelIndex &idx); 46 | QModelIndex move_down(const QModelIndex &idx); 47 | std::vector get_ingredients(void) { return m_ingredients; } 48 | std::vector > get_sections(void) { return m_sections; } 49 | bool has_acceptable_input(void); 50 | protected: 51 | std::vector m_ingredients; 52 | std::vector > m_sections; 53 | }; 54 | -------------------------------------------------------------------------------- /.github/workflows/anymeal.yml: -------------------------------------------------------------------------------- 1 | name: AnyMeal CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | ubuntu-build-and-test: 11 | runs-on: ubuntu-latest 12 | container: 13 | image: ubuntu:latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | - name: Install depdendencies 17 | run: | 18 | apt -y update 19 | apt -y install autoconf build-essential git flex googletest 20 | apt -y install libqt6svg6 libsqlite3-dev qt6-base-dev 21 | apt -y install qt6-tools-dev-tools qt6-base-dev-tools pkgconf 22 | - name: autoreconf 23 | run: ./autogen.sh 24 | - name: configure 25 | run: ./configure 26 | - name: make 27 | run: make 28 | - name: check 29 | run: make check 30 | - name: distributable 31 | run: make dist-xz 32 | - name: upload 33 | uses: actions/upload-artifact@v4 34 | with: 35 | name: anymeal-source 36 | path: anymeal-*.tar.xz 37 | fedora-build-and-test: 38 | name: fedora-build-and-test 39 | runs-on: ubuntu-latest 40 | container: 41 | image: fedora:latest 42 | steps: 43 | - uses: actions/checkout@v4 44 | - name: install dependencies 45 | run: | 46 | dnf -y update 47 | dnf -y install automake binutils flex gcc-c++ git gtest-devel 48 | dnf -y install make pkgconf qt6-qtbase-devel qt6-qtsvg-devel 49 | dnf -y install qt6-qttools-devel sqlite-devel which 50 | - name: autoreconf 51 | run: ./autogen.sh 52 | - name: configure 53 | run: ./configure 54 | - name: make 55 | run: make 56 | - name: make check 57 | run: make check 58 | windows-installer: 59 | runs-on: windows-2025 60 | defaults: 61 | run: 62 | shell: msys2 {0} 63 | steps: 64 | - uses: actions/checkout@v4 65 | - uses: msys2/setup-msys2@v2 66 | with: 67 | release: false 68 | install: >- 69 | mingw-w64-x86_64-gcc mingw-w64-x86_64-make autoconf automake make flex 70 | bison git libtool mingw-w64-x86_64-sqlite3 mingw-w64-x86_64-gtest 71 | mingw-w64-x86_64-iconv mingw-w64-x86_64-qt6-base 72 | mingw-w64-x86_64-qt6-declarative mingw-w64-x86_64-qt6-svg 73 | mingw-w64-x86_64-qt6-tools mingw-w64-x86_64-pkgconf mingw-w64-x86_64-nsis 74 | mingw-w64-x86_64-icu mingw-w64-x86_64-libiconv mingw-w64-x86_64-pcre 75 | mingw-w64-x86_64-pcre2 76 | - name: autoreconf 77 | run: ./autogen.sh 78 | - name: configure 79 | run: ./configure.mingw 80 | - name: make 81 | run: make 82 | - name: check 83 | run: make check 84 | - name: nsis 85 | run: makensis anymeal.nsi 86 | - name: upload 87 | uses: actions/upload-artifact@v4 88 | with: 89 | name: anymeal-installer 90 | path: anymeal-installer-*.exe 91 | -------------------------------------------------------------------------------- /anymeal/category_dialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | CategoryDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 319 10 | 92 11 | 12 | 13 | 14 | Choose Category 15 | 16 | 17 | 18 | :/images/anymeal.png:/images/anymeal.png 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | &Category 27 | 28 | 29 | category_edit 30 | 31 | 32 | 33 | 34 | 35 | 36 | 40 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | Qt::Vertical 46 | 47 | 48 | 49 | 20 50 | 1 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | Qt::Horizontal 59 | 60 | 61 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | buttonBox 73 | accepted() 74 | CategoryDialog 75 | accept() 76 | 77 | 78 | 224 79 | 66 80 | 81 | 82 | 157 83 | 91 84 | 85 | 86 | 87 | 88 | buttonBox 89 | rejected() 90 | CategoryDialog 91 | reject() 92 | 93 | 94 | 292 95 | 72 96 | 97 | 98 | 286 99 | 91 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /tests/test_partition.cc: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2021, 2023 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #include 17 | #include 18 | #include "partition.hh" 19 | 20 | 21 | using namespace testing; 22 | using namespace std; 23 | 24 | 25 | TEST(PartitionTest, EmptyFile) { 26 | istringstream s(""); 27 | ASSERT_TRUE(recipes(s).empty()); 28 | } 29 | 30 | TEST(PartitionTest, MinimalRecipe) { 31 | istringstream s("MMMMM---MEAL-MASTER Format---\r\nMMMMM"); 32 | ASSERT_EQ(1, recipes(s).size()); 33 | } 34 | 35 | TEST(PartitionTest, RecipeContent) { 36 | istringstream s("MMMMM---MEAL-MASTER Format---\r\nMMMMM"); 37 | ASSERT_EQ("MMMMM---MEAL-MASTER Format---\r\nMMMMM\r\n", recipes(s)[0]); 38 | } 39 | 40 | TEST(PartitionTest, ConvertUnixLF) { 41 | istringstream s("MMMMM---MEAL-MASTER Format---\nMMMMM"); 42 | ASSERT_EQ("MMMMM---MEAL-MASTER Format---\r\nMMMMM\r\n", recipes(s)[0]); 43 | } 44 | 45 | TEST(PartitionTest, IgnoreStrayText) { 46 | istringstream s("text"); 47 | ASSERT_TRUE(recipes(s).empty()); 48 | } 49 | 50 | TEST(PartitionTest, EndOfRecipe) { 51 | istringstream s("MMMMM---MEAL-MASTER Format---\r\nMMMMM\r\ntext"); 52 | ASSERT_EQ("MMMMM---MEAL-MASTER Format---\r\nMMMMM\r\n", recipes(s)[0]); 53 | } 54 | 55 | TEST(PartitionTest, TwoRecipes) { 56 | istringstream s("MMMMM---MEAL-MASTER Format---\r\nMMMMM\r\nMMMMM---Recipe via Meal-Master\r\nMMMMM"); 57 | vector result = recipes(s); 58 | ASSERT_EQ(2, result.size()); 59 | EXPECT_EQ("MMMMM---MEAL-MASTER Format---\r\nMMMMM\r\n", result[0]); 60 | EXPECT_EQ("MMMMM---Recipe via Meal-Master\r\nMMMMM\r\n", result[1]); 61 | } 62 | 63 | TEST(PartitionTest, AlternateSeparator) { 64 | istringstream s("--------MEAL-MASTER Format---\r\n-----"); 65 | EXPECT_EQ("--------MEAL-MASTER Format---\r\n-----\r\n", recipes(s)[0]); 66 | } 67 | 68 | TEST(PartitionTest, RecipeWithSection) { 69 | istringstream s("MMMMM---MEAL-MASTER Format-----\r\nMMMMM----section-----\r\nMMMMM\r\n"); 70 | EXPECT_EQ("MMMMM---MEAL-MASTER Format-----\r\nMMMMM----section-----\r\nMMMMM\r\n", recipes(s)[0]); 71 | } 72 | 73 | TEST(PartitionTest, CheckRecipeIsClosed) { 74 | istringstream s("MMMMM---MEAL-MASTER Format---\r\nMMMMM"); 75 | bool unexpected_eof = true; 76 | recipes(s, &unexpected_eof); 77 | ASSERT_FALSE(unexpected_eof); 78 | } 79 | 80 | TEST(PartitionTest, UnexpectedEndOfFile) { 81 | istringstream s("MMMMM---MEAL-MASTER Format---\r\n"); 82 | bool unexpected_eof = false; 83 | recipes(s, &unexpected_eof); 84 | ASSERT_TRUE(unexpected_eof); 85 | } 86 | 87 | -------------------------------------------------------------------------------- /anymeal/recipe.hh: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2023 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #pragma once 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "ingredient.hh" 22 | 23 | 24 | class Recipe 25 | { 26 | public: 27 | Recipe(void): m_servings(0) {} 28 | void set_title(const char *title) { m_title = title; } 29 | std::string title(void) { return m_title; } 30 | const char *title_c_str(void) { return m_title.c_str(); } 31 | std::set &categories(void) { return m_categories; } 32 | void add_category(const char *category) { m_categories.insert(category); } 33 | int servings(void) { return m_servings; } 34 | void set_servings(int servings) { m_servings = servings; } 35 | std::string &servings_unit(void) { return m_servings_unit; } 36 | const char *servings_unit_c_str(void) { return m_servings_unit.c_str(); } 37 | void set_servings_unit(const char *servings_unit) { m_servings_unit = servings_unit; } 38 | std::vector &ingredients(void) { return m_ingredients; } 39 | void add_ingredient(const Ingredient &ingredient) { m_ingredients.push_back(ingredient); } 40 | void set_ingredients(const std::vector &ingredients) { m_ingredients = ingredients; } 41 | std::vector > &ingredient_sections(void) { return m_ingredient_sections; } 42 | void add_ingredient_section(int row, const char *title); 43 | void set_ingredient_sections(const std::vector > §ions) { m_ingredient_sections = sections; } 44 | std::vector &instructions(void) { return m_instructions; } 45 | void add_instruction(const char *instruction) { m_instructions.push_back(instruction); } 46 | void append_instruction(const char *instruction); 47 | void set_instructions(const std::vector &instructions) { m_instructions = instructions; } 48 | std::vector > &instruction_sections(void) { return m_instruction_sections; } 49 | void add_instruction_section(int row, const char *title); 50 | void set_instruction_sections(const std::vector > §ions) { m_instruction_sections = sections; } 51 | protected: 52 | std::string m_title; 53 | std::set m_categories; 54 | int m_servings; 55 | std::string m_servings_unit; 56 | std::vector m_ingredients; 57 | std::vector > m_ingredient_sections; 58 | std::vector m_instructions; 59 | std::vector > m_instruction_sections; 60 | }; 61 | -------------------------------------------------------------------------------- /debian/upstream/signing-key.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP PUBLIC KEY BLOCK----- 2 | 3 | mQINBGObqGoBEAC5d/80KSScSvAFGoq6DEmJX11MPjkkUySNb+ljcsc0n/fJ08FP 4 | Ug654AV7UlHe7+LlxhRzKoGy5pvgV1q16eS5jJLRMPrVQmZHES1sT5h7XwCq/oxn 5 | Pl8Smr1+MIGE51vaMrXL/absSRWTDD7X+SRxmVxXB3Ou+mShkYij59nSXTTyQV9o 6 | Eh3F6DIM+QLBC8pvdB/TqoVkvlkJGUdbfzoHBGbd3cYu48q87Y/TBLqnhPwYW3WE 7 | wrXgS7+PT2wHD1OcWjmRvcBE/NeBDaJcN+19LEcwlAnRxiSbEDyBAwobDrKQ2VVC 8 | NlCHtP1b5AvWtRKR9tItzaeT9z2MumrjnMSlvPZEqUBczW1bnKBnqGCljBJdpomp 9 | +FdEkrxhj/aogLGOj2F1kB4WYkLyELzw+P4nkKsk1cKKxtyLCn7OHidnejdaZqCI 10 | 0FZb7lvPfZld3sYABaVhc2x2VbPPCpi3bjsNFt3kqPDAmzRCPpCncPBrEj38SOWb 11 | +1XrGjV0ybzRryk+5pGVRzG/0XpS+LJ9EIPTtY2NvufCueulGiux49ypcIYO8UWg 12 | 6GNtaDsbO6c6OG7TvlfLOCkfk3+UxNTCPjEgcdNTP7HXR56q9M6srW4wiURBG3jR 13 | bZ/jppygDT7CZtoR68jpk7Kjib51h3Tc7aTSxTeVbajxLbk0CeS+S86fCwARAQAB 14 | tB5KYW4gV2VkZWtpbmQgPGphbkB3ZWRlc29mdC5kZT6JAlQEEwEKAD4WIQQLoAb9 15 | /zS1xrN5NLBzIVSfb44fzwUCY5uoagIbAwUJA8JnAAULCQgHAwUVCgkICwUWAgMB 16 | AAIeAQIXgAAKCRBzIVSfb44fz6XdD/9fNuOLui9ekJGKqIfz6InSz1/HHnJESoqW 17 | yXJ+OraTa9gYs13DyiZtd9HHj20JVTdKDILX3Ve8DDtAsVrfSAMxKBWnzRqeBPgS 18 | TuQG+G5jW7qi4HO9U2Zy1nCmfOYZfRLRE0KpVenRrfUpBRC+NRyBR5XwalQKXT4x 19 | urEU3CdIXJmzrRB7X74b5vru6+6LZravCunFSYozbTD/qEw+RMW4boulkg7V+VZK 20 | tyTHmG0wzWz2m3TJ7MpfEsuPE6ysEGuFNo7L5kOihyD6X8HND4n/ZJJbK17KFfFV 21 | Yroz1dWY2e0m8HSxKbdBa2bIBF8oCH8o6bVpOgaxXosUjlapQJk5quOIHh8ZQOun 22 | 8k5xI4htVZfDVgMt1evs8v7/3xH2h+yDYX7QxABDsGbZMHU2fNH7PTTJei3978pk 23 | EHiWWmUssuZnQR2MAtGfHdXqATbxdxxOg6s9NSf1Bh5bYuNqT3R52vB0AcMbFmOV 24 | KG4QuYWFKqvcHqABo+37e1VExL4kn3kCOB6N2qynXLfkQqVh1qAc1liwiuhB62Hg 25 | 9U6inIuLwal/deolr17fAKOe3KjsRMsh05gCZS0R0BKW6gQAcHDQT4VRZHZnZQqc 26 | fgkwiFcU7GLgsxFEM8K4hU3upi9611NN2a2BQS1Mh3bs7kyoGYgfK+GpVc91g6x6 27 | TJsHpEHiGrkCDQRjm6hqARAAzktfPmCb2mp/9pAkckSzyN4CMPAb0+X7ta96l/Gj 28 | 2vCIdl8Q/jHHelXGR+SBdfT+22PcgFtjPz1vcMxjroLzqD13quYpODz3zBQaafR3 29 | MwzzKes6v41ciejzBcdXxvIBYCNdfq8uEvq5QHuSImJpB9BkxjJwSqOEzrv1rscJ 30 | NVR+dCEq+HBaA7jlfsA5UhSvLdl5xRhktzNvyL7umBUTAU6MEDIJvto0VJxS2A8c 31 | UTDCMuJDSXVq4jI8lVYAsbXxaFfbPhRyXCmbRjwV+/L1dZZz1jnJ1hY4SlaU0zpS 32 | Yk6bz+yrtYgpBDDcxJg/KZTYqyDBOqcZ1DykiKxhaJhTJ2KMNs0JLp5+RKt74005 33 | 4ijVERmTnCR7OXug+OzDDGT08G57Va1VtFFRVeBi2U4gCo9KeBORuPUE/7rMux62 34 | XeKYzJFbwP4lT4Tx7eGZm5HIcKasn/fVcBoABWvIVCE/XsLl7g3S8e0q6KJkAf8k 35 | zjy4+h+lnHYZAyDQG47GPS7k7Xn7vcZL3k/uDkNBYGJo91BLZ0qqSRgmmf2euZY9 36 | Gc9mX6Ui6EpsgehHfUfJ7vlYYAeM4ims0gHXlw/7wLfD34fwWZeFrNCjbRG7X/hn 37 | IPyoNMAunZM9jXOjlSZ7iuiEltUrZ+K569KveUvg7ajvMlRMjKIHeu/JMfaoG2jA 38 | 3SUAEQEAAYkCPAQYAQoAJhYhBAugBv3/NLXGs3k0sHMhVJ9vjh/PBQJjm6hqAhsM 39 | BQkDwmcAAAoJEHMhVJ9vjh/PsRYP/R1Cfii/T9zLVU/nMibCl+k+PubOZNqbE25G 40 | w2cM+q0GgU3/CaR9rOJIt2nCKHokAGdSA7eiDMkntQS2+NOJSFYXevwIwXd4N4tk 41 | if8PCLi2qAGsbEP7GHT+c0U7yFoU9sarFc7PIpKfF3iHszsiBEKDUHRLOi5h+RDS 42 | 14yUcMgmsoPSUXtCGRHcyo3e5o5pjo4x0B5fO+Rh0c8eD6POZyqTSbWF3IAMOLPR 43 | +DIdZp4tbMkT83M++FRLgVveGqUY7d/wky1EGjyg5kM2WONSrPp+9LBMkkKKuKY+ 44 | ++ky/dkXeyJ7BlJnwLr8Ab/rHw9qcyk3r631xp9SG1tfn3oBcvIXMM2YbayjnLLb 45 | eHBqxNOI1t2nFkEcGdsV8blb1KCTn5c4nGUcCrcTPNRajlcd5LiMBHFiilIXwP/m 46 | SllCEizZPq5wG7TDHr+FsbwRF1muOlTsLdHcx7iHH2oF4s11/F3An9QM0s3H8NAD 47 | sgFH5NKfZBD5hMf6gtQgWtDWGIj9wZs4IssQCdewPg0l/ZR2sG562VHm8cUvwq9e 48 | zc4YjzFcig/u60eshgAVA9pqaLd2VhoOlIsmAxW/8/Tq2PRoxJfwtaexojRwBX90 49 | m6n7MjrOklJxOKsFb15/LMhMEg/sjHhVAVo5KxjkM+/oh+mk2IFm022aoykPMp/x 50 | fk+b2Pzh 51 | =2DEn 52 | -----END PGP PUBLIC KEY BLOCK----- 53 | -------------------------------------------------------------------------------- /anymeal/Makefile.am: -------------------------------------------------------------------------------- 1 | SUFFIXES = .ui .qrc .cc .hh .ll .rc .o 2 | 3 | SUBDIRS = locale 4 | 5 | bin_PROGRAMS = anymeal 6 | 7 | noinst_LIBRARIES = libanymeal.a 8 | 9 | noinst_HEADERS = main_window.hh partition.hh mealmaster.hh recipe.hh ingredient.hh recode.hh database.hh titles_model.hh \ 10 | categories_model.hh html.hh export.hh import_dialog.hh export_dialog.hh edit_dialog.hh ingredient_model.hh \ 11 | instructions_model.hh category_dialog.hh converter_window.hh category_picker.hh category_table_model.hh \ 12 | rename_dialog.hh merge_dialog.hh add_dialog.hh 13 | 14 | EXTRA_DIST = main_window.ui import_dialog.ui export_dialog.ui edit_dialog.ui category_picker.ui category_dialog.ui \ 15 | converter_window.ui rename_dialog.ui merge_dialog.ui add_dialog.ui anymeal.qrc anymeal.png anymeal.ico \ 16 | de.wedesoft.anymeal.desktop anymeal.man categoryadd.svg categoryremove.svg delete.svg down.svg edit.svg export.svg \ 17 | import.svg preview.svg print.svg quit.svg search.svg trash.svg up.svg calculator.svg duplicate.svg new.svg \ 18 | flag_uk.svg flag_de.svg flag_fr.svg flag_it.svg flag_nl.svg flag_sl.svg \ 19 | splash.png header.bmp de.wedesoft.anymeal.appdata.xml 20 | 21 | BUILT_SOURCES = ui_main_window.hh ui_import_dialog.hh ui_export_dialog.hh ui_edit_dialog.hh ui_category_dialog.hh \ 22 | ui_converter_window.hh ui_category_picker.hh ui_rename_dialog.hh ui_merge_dialog.hh ui_add_dialog.hh \ 23 | moc_main_window.cc moc_import_dialog.cc moc_export_dialog.cc moc_edit_dialog.cc moc_category_picker.cc \ 24 | moc_ingredient_model.cc moc_titles_model.cc moc_categories_model.cc moc_instructions_model.cc \ 25 | moc_category_dialog.cc moc_converter_window.cc moc_category_table_model.cc moc_rename_dialog.cc \ 26 | moc_merge_dialog.cc moc_add_dialog.cc qrc_anymeal.cc 27 | 28 | anymeal_SOURCES = anymeal.cc main_window.cc import_dialog.cc export_dialog.cc edit_dialog.cc category_picker.cc \ 29 | converter_window.cc ingredient_model.cc titles_model.cc categories_model.cc instructions_model.cc \ 30 | category_dialog.cc category_table_model.cc rename_dialog.cc merge_dialog.cc add_dialog.cc \ 31 | moc_import_dialog.cc moc_main_window.cc moc_export_dialog.cc moc_edit_dialog.cc moc_ingredient_model.cc \ 32 | moc_titles_model.cc moc_categories_model.cc moc_instructions_model.cc moc_category_dialog.cc \ 33 | moc_category_picker.cc moc_converter_window.cc moc_category_table_model.cc moc_rename_dialog.cc \ 34 | moc_merge_dialog.cc moc_add_dialog.cc qrc_anymeal.cc 35 | if HAVE_WINDRES 36 | anymeal_SOURCES += icon.rc 37 | endif 38 | anymeal_CXXFLAGS = $(SQLITE3_CFLAGS) $(QT_CXXFLAGS) 39 | anymeal_LDFLAGS = 40 | anymeal_LDADD = libanymeal.a $(SQLITE3_LDFLAGS) $(QT_LIBS) 41 | 42 | libanymeal_a_SOURCES = partition.cc recipe.cc ingredient.cc mealmaster.ll recode.cc database.cc html.cc export.cc 43 | libanymeal_a_CXXFLAGS = 44 | libanymeal_a_LIBADD = 45 | 46 | CLEANFILES = $(BUILT_SOURCES) 47 | 48 | appdir = $(datadir)/applications 49 | app_DATA = de.wedesoft.anymeal.desktop 50 | 51 | icondir = $(datadir)/icons/hicolor/64x64/apps 52 | icon_DATA = anymeal.png 53 | 54 | metainfodir = $(datadir)/metainfo 55 | metainfo_DATA = de.wedesoft.anymeal.appdata.xml 56 | 57 | man1_MANS = anymeal.man 58 | 59 | ui_%.hh: %.ui $(QT_UIC) 60 | $(QT_UIC) -o $@ $< 61 | 62 | moc_%.cc: %.hh $(QT_MOC) 63 | $(QT_MOC) -o $@ $< 64 | 65 | qrc_%.cc: %.qrc $(QT_RCC) 66 | $(QT_RCC) -o $@ $< 67 | 68 | .rc.o: 69 | $(WINDRES) $< -O coff -o $@ 70 | -------------------------------------------------------------------------------- /tests/test_recode.cc: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2021, 2023 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #include 17 | #include "recode.hh" 18 | 19 | 20 | using namespace testing; 21 | using namespace std; 22 | 23 | TEST(RecodeTest, Constructor) { 24 | Recoder r("ISO-8859-1", "UTF-8"); 25 | } 26 | 27 | TEST(RecodeTest, NoSuchEncoding) { 28 | EXPECT_THROW(Recoder("ISO-8859-1", "unknown"), recode_exception); 29 | } 30 | 31 | TEST(RecodeTest, RecodeString) { 32 | Recoder r("ISO-8859-1", "UTF-8"); 33 | string s("\xc4pfel"); 34 | EXPECT_EQ("Äpfel", r.process(s)); 35 | } 36 | 37 | TEST(RecodeTest, RecodeException) { 38 | Recoder r("ISO-8859-1", "US-ASCII"); 39 | string s("\xc4pfel"); 40 | EXPECT_THROW(r.process(s), recode_exception); 41 | } 42 | 43 | TEST(RecodeTest, RecodeIngredient) { 44 | Recoder r("ISO-8859-1", "UTF-8"); 45 | Ingredient ingredient; 46 | ingredient.set_amount_integer(2); 47 | ingredient.set_amount_numerator(3); 48 | ingredient.set_amount_denominator(5); 49 | ingredient.set_amount_float(2.6); 50 | ingredient.set_unit("g "); 51 | ingredient.add_text("\xc4pfel"); 52 | Ingredient result = r.process_ingredient(ingredient); 53 | EXPECT_EQ(2, result.amount_integer()); 54 | EXPECT_EQ(3, result.amount_numerator()); 55 | EXPECT_EQ(5, result.amount_denominator()); 56 | EXPECT_EQ(2.6, result.amount_float()); 57 | EXPECT_EQ("g ", result.unit()); 58 | EXPECT_EQ("Äpfel", result.text()); 59 | } 60 | 61 | TEST(RecodeTest, RecodeRecipe) { 62 | Recoder r("ISO-8859-1", "UTF-8"); 63 | Recipe recipe; 64 | recipe.set_title("K\xfc""chlein"); 65 | recipe.add_category("Geb\xe4""ck"); 66 | recipe.set_servings(4); 67 | recipe.set_servings_unit("Porti\xf6nchen"); 68 | Ingredient ingredient; 69 | ingredient.add_text("\xc4pfel"); 70 | recipe.add_ingredient(ingredient); 71 | recipe.add_ingredient_section(1, "Teilst\xfc""ck"); 72 | recipe.add_instruction("Teig anr\xfchren"); 73 | recipe.add_instruction_section(1, "R\xfchren"); 74 | Recipe result = r.process_recipe(recipe); 75 | EXPECT_EQ("Küchlein", result.title()); 76 | ASSERT_EQ(1, result.categories().size()); 77 | EXPECT_EQ("Gebäck", *result.categories().begin()); 78 | EXPECT_EQ(4, result.servings()); 79 | EXPECT_EQ("Portiönchen", result.servings_unit()); 80 | EXPECT_EQ(1, result.ingredients().size()); 81 | EXPECT_EQ("Äpfel", result.ingredients()[0].text()); 82 | EXPECT_EQ(1, result.ingredient_sections().size()); 83 | EXPECT_EQ(1, result.ingredient_sections()[0].first); 84 | EXPECT_EQ("Teilstück", result.ingredient_sections()[0].second); 85 | EXPECT_EQ(1, result.instructions().size()); 86 | EXPECT_EQ("Teig anrühren", result.instructions()[0]); 87 | EXPECT_EQ(1, result.instruction_sections().size()); 88 | EXPECT_EQ(1, result.instruction_sections()[0].first); 89 | EXPECT_EQ("Rühren", result.instruction_sections()[0].second); 90 | } 91 | -------------------------------------------------------------------------------- /anymeal/main_window.hh: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2023 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #pragma once 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include "ui_main_window.hh" 24 | #include "database.hh" 25 | #include "category_picker.hh" 26 | #include "titles_model.hh" 27 | #include "categories_model.hh" 28 | #include "category_table_model.hh" 29 | #include "converter_window.hh" 30 | #include "import_dialog.hh" 31 | #include "export_dialog.hh" 32 | #include "recipe.hh" 33 | 34 | 35 | class gui_exception: public std::exception 36 | { 37 | public: 38 | gui_exception(const std::string &error): m_error(error) {} 39 | virtual ~gui_exception(void) throw() {} 40 | virtual const char *what(void) const throw() { return m_error.c_str(); } 41 | protected: 42 | std::string m_error; 43 | }; 44 | 45 | typedef enum { EDIT_CURRENT = 0, EDIT_COPY, EDIT_NEW, EDIT_CANCEL } EditMode; 46 | 47 | class MainWindow: public QMainWindow 48 | { 49 | Q_OBJECT 50 | public: 51 | MainWindow(QWidget *parent=NULL); 52 | static std::string translate(const char *context, const char *text); 53 | std::vector recipe_ids(void); 54 | void show_num_recipes(void); 55 | EditMode editing_mode(void); 56 | Recipe default_recipe(void); 57 | void edit_recipe(EditMode mode); 58 | void show_search_history(const char *type, const char *text); 59 | void reset_search_history(void); 60 | void switch_language(const QString &country); 61 | void switch_and_set_language(const char *country); 62 | void set_recipe(Recipe recipe); 63 | public slots: 64 | void import(void); 65 | void new_recipe(void); 66 | void edit(void); 67 | void collect_garbage(void); 68 | void about(void); 69 | void filter(void); 70 | void reset(void); 71 | void selected(const QModelIndex ¤t, const QModelIndex &previous); 72 | void titles_context_menu(const QPoint &pos); 73 | void recipe_context_menu(const QPoint &pos); 74 | void export_recipes(void); 75 | void delete_recipes(void); 76 | void preview(void); 77 | void print(void); 78 | void add_to_category(void); 79 | void remove_from_category(void); 80 | void render(QPrinter *printer); 81 | void language_en(void); 82 | void language_de(void); 83 | void language_fr(void); 84 | void language_it(void); 85 | void language_nl(void); 86 | void language_sl(void); 87 | void open_converter(void); 88 | void remove_duplicates(void); 89 | protected: 90 | bool eventFilter(QObject *object, QEvent *event); 91 | Ui::MainWindow m_ui; 92 | QSettings m_settings; 93 | Recipe m_recipe; 94 | QTranslator *m_translator; 95 | Database m_database; 96 | ConverterWindow m_converter_window; 97 | ImportDialog m_import_dialog; 98 | ExportDialog m_export_dialog; 99 | CategoryPicker m_category_picker; 100 | TitlesModel *m_titles_model; 101 | CategoriesModel *m_categories_model; 102 | CategoryTableModel *m_category_table_model; 103 | QCompleter *m_categories_completer; 104 | QMenu *m_titles_context_menu; 105 | QMenu *m_recipe_context_menu; 106 | }; 107 | -------------------------------------------------------------------------------- /anymeal/recode.cc: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2025 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include "recode.hh" 21 | 22 | 23 | using namespace std; 24 | 25 | Recoder::Recoder(const char *fromcode, const char *tocode) { 26 | m_request = iconv_open(tocode, fromcode); 27 | if (m_request == (iconv_t)-1) { 28 | ostringstream s; 29 | s << "Cannot fulfill recoding request from " << fromcode << " to " << tocode << ": " << strerror(errno); 30 | throw recode_exception(s.str()); 31 | }; 32 | } 33 | 34 | Recoder::~Recoder(void) { 35 | iconv_close(m_request); 36 | } 37 | 38 | string Recoder::process(const std::string &text) { 39 | char *inbuf = (char *)text.c_str(); 40 | size_t inbytesleft = text.length(); 41 | size_t outbytesleft = 4 * text.length(); 42 | char *outbuf = (char *)malloc(outbytesleft * sizeof(char)); 43 | char *output = outbuf; 44 | iconv(m_request, NULL, NULL, NULL, NULL); // reset conversion state. 45 | size_t result = iconv(m_request, &inbuf, &inbytesleft, &outbuf, &outbytesleft); 46 | if (result == (size_t)-1) { 47 | free(output); 48 | ostringstream s; 49 | s << "Failed to recode string \"" << text << "\": " << strerror(errno); 50 | throw recode_exception(s.str()); 51 | }; 52 | size_t output_length = outbuf - output; 53 | string retval(output, output_length); 54 | free(output); 55 | return retval; 56 | } 57 | 58 | Ingredient Recoder::process_ingredient(Ingredient &ingredient) { 59 | Ingredient result; 60 | result.set_amount_integer(ingredient.amount_integer()); 61 | result.set_amount_numerator(ingredient.amount_numerator()); 62 | result.set_amount_denominator(ingredient.amount_denominator()); 63 | result.set_amount_float(ingredient.amount_float()); 64 | result.set_unit(ingredient.unit_c_str()); 65 | result.add_text(process(ingredient.text()).c_str()); 66 | return result; 67 | } 68 | 69 | Recipe Recoder::process_recipe(Recipe &recipe) { 70 | Recipe result; 71 | result.set_title(process(recipe.title()).c_str()); 72 | for (set::iterator category=recipe.categories().begin(); category!=recipe.categories().end(); category++) 73 | result.add_category(process(*category).c_str()); 74 | result.set_servings(recipe.servings()); 75 | result.set_servings_unit(process(recipe.servings_unit()).c_str()); 76 | for (vector::iterator ingredient=recipe.ingredients().begin(); ingredient!=recipe.ingredients().end(); ingredient++) 77 | result.add_ingredient(process_ingredient(*ingredient)); 78 | for (vector >::iterator section=recipe.ingredient_sections().begin(); section!=recipe.ingredient_sections().end(); section++) 79 | result.add_ingredient_section(section->first, process(section->second).c_str()); 80 | for (vector::iterator instruction=recipe.instructions().begin(); instruction!=recipe.instructions().end(); instruction++) 81 | result.add_instruction(process(*instruction).c_str()); 82 | for (vector >::iterator section=recipe.instruction_sections().begin(); section!=recipe.instruction_sections().end(); section++) 83 | result.add_instruction_section(section->first, process(section->second).c_str()); 84 | return result; 85 | } 86 | -------------------------------------------------------------------------------- /anymeal/category_picker.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | CategoryPicker 4 | 5 | 6 | 7 | 0 8 | 0 9 | 440 10 | 543 11 | 12 | 13 | 14 | Category Picker 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | QAbstractItemView::ExtendedSelection 28 | 29 | 30 | QAbstractItemView::SelectRows 31 | 32 | 33 | true 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | &Add 45 | 46 | 47 | 48 | 49 | 50 | 51 | &Delete 52 | 53 | 54 | 55 | 56 | 57 | 58 | &Rename 59 | 60 | 61 | 62 | 63 | 64 | 65 | &Merge 66 | 67 | 68 | 69 | 70 | 71 | 72 | Qt::Vertical 73 | 74 | 75 | 76 | 20 77 | 40 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | Qt::Horizontal 90 | 91 | 92 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | button_box 102 | accepted() 103 | CategoryPicker 104 | accept() 105 | 106 | 107 | 248 108 | 254 109 | 110 | 111 | 157 112 | 274 113 | 114 | 115 | 116 | 117 | button_box 118 | rejected() 119 | CategoryPicker 120 | reject() 121 | 122 | 123 | 316 124 | 260 125 | 126 | 127 | 286 128 | 274 129 | 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Source: https://github.com/wedesoft/anymeal 3 | Upstream-Name: anymeal 4 | Upstream-Contact: Jan Wedekind 5 | 6 | Files: * 7 | Copyright: 2002, 2003, 2004, 2005, 2006, 2020, 2021, 2022, 2023 Jan Wedekind 8 | License: GPL-3+ 9 | This program is free software: you can redistribute it and/or modify it 10 | under the terms of the GNU General Public License as published by the 11 | Free Software Foundation, either version 3 of the License, or (at your 12 | option) any later version. 13 | . 14 | This program is distributed in the hope that it will be useful, but 15 | WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 17 | Public License for more details. 18 | . 19 | You should have received a copy of the GNU General Public License along 20 | with this program. If not, see . 21 | . 22 | The GNU General Public License version 3 may be found on Debian systems 23 | in /usr/share/common-licenses/GPL-3. 24 | 25 | Files: m4/ax_have_qt.m4 26 | Copyright: 2008, Bastiaan Veelo 27 | License: GNU-All-Permissive-License 28 | Copying and distribution of this file, with or without modification, are 29 | permitted in any medium without royalty provided the copyright notice 30 | and this notice are preserved. This file is offered as-is, without any 31 | warranty. 32 | 33 | Files: m4/ax_lib_sqlite3.m4 34 | Copyright: 2008, Mateusz Loskot 35 | License: GNU-All-Permissive-License 36 | Copying and distribution of this file, with or without modification, are 37 | permitted in any medium without royalty, provided the copyright notice and 38 | this notice are preserved. This file is offered as-is, without any warranty. 39 | 40 | Files: anymeal/*.svg 41 | Copyright: 2008, 2009, 2010, 2011, 2012, 2013, 2014, The Oxygen Team 42 | License: LGPL-3+ 43 | This library is free software; you can redistribute it and/or 44 | modify it under the terms of the GNU Lesser General Public 45 | License as published by the Free Software Foundation; either 46 | version 3 of the License, or (at your option) any later version. 47 | . 48 | This library is distributed in the hope that it will be useful, 49 | but WITHOUT ANY WARRANTY; without even the implied warranty of 50 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 51 | Lesser General Public License for more details. 52 | . 53 | The complete text of the GNU Lesser General Public License version 3 can be 54 | found in the file `/usr/share/common-licenses/GPL-3'. 55 | 56 | Files: tests/gtest-all.cc 57 | Copyright: 2008, Google Inc. 58 | License: BSD-3-clause 59 | Copyright 2008, Google Inc. 60 | All rights reserved. 61 | . 62 | Redistribution and use in source and binary forms, with or without 63 | modification, are permitted provided that the following conditions are 64 | met: 65 | . 66 | * Redistributions of source code must retain the above copyright 67 | notice, this list of conditions and the following disclaimer. 68 | * Redistributions in binary form must reproduce the above 69 | copyright notice, this list of conditions and the following disclaimer 70 | in the documentation and/or other materials provided with the 71 | distribution. 72 | * Neither the name of Google Inc. nor the names of its 73 | contributors may be used to endorse or promote products derived from 74 | this software without specific prior written permission. 75 | . 76 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 77 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 78 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 79 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 80 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 81 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 82 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 83 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 84 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 85 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 86 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 87 | -------------------------------------------------------------------------------- /anymeal/category_picker.cc: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2025 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #include 17 | #include 18 | #include "category_picker.hh" 19 | #include "add_dialog.hh" 20 | #include "rename_dialog.hh" 21 | #include "merge_dialog.hh" 22 | 23 | using namespace std; 24 | 25 | CategoryPicker::CategoryPicker(QWidget *parent): 26 | QDialog(parent), m_sort_filter_proxy_model(this), m_model(NULL) 27 | { 28 | m_ui.setupUi(this); 29 | m_sort_filter_proxy_model.setSortCaseSensitivity(Qt::CaseInsensitive); 30 | m_sort_filter_proxy_model.setFilterCaseSensitivity(Qt::CaseInsensitive); 31 | connect(m_ui.add_button, &QPushButton::clicked, this, &CategoryPicker::add_category); 32 | connect(m_ui.delete_button, &QPushButton::clicked, this, &CategoryPicker::delete_categories); 33 | connect(m_ui.rename_button, &QPushButton::clicked, this, &CategoryPicker::rename_category); 34 | connect(m_ui.merge_button, &QPushButton::clicked, this, &CategoryPicker::merge_category); 35 | connect(m_ui.filter_edit, &QLineEdit::textChanged, &m_sort_filter_proxy_model, &QSortFilterProxyModel::setFilterFixedString); 36 | } 37 | 38 | void CategoryPicker::set_model(CategoryTableModel *model) { 39 | m_model = model; 40 | m_sort_filter_proxy_model.setSourceModel(model); 41 | m_ui.category_table->setModel(&m_sort_filter_proxy_model); 42 | } 43 | 44 | void CategoryPicker::add_category(void) { 45 | AddDialog add_dialog(this); 46 | add_dialog.set_model(m_model); 47 | if (add_dialog.exec() == QDialog::Accepted) { 48 | QModelIndex source_index = m_model->add_category(add_dialog.name()); 49 | QModelIndex index = m_sort_filter_proxy_model.mapFromSource(source_index); 50 | m_ui.category_table->setCurrentIndex(index); 51 | }; 52 | } 53 | 54 | void CategoryPicker::delete_categories(void) { 55 | if (QMessageBox::question(this, tr("Delete Categories"), tr("Do you want to delete the selected categories?")) == QMessageBox::Yes) { 56 | QItemSelectionModel *selection_model = m_ui.category_table->selectionModel(); 57 | QModelIndexList index_list = selection_model->selectedRows(); 58 | QModelIndexList mapped_list = QModelIndexList(); 59 | for (QModelIndexList::iterator i=index_list.begin(); i!=index_list.end(); i++) { 60 | QModelIndex source_index = m_sort_filter_proxy_model.mapToSource(*i); 61 | mapped_list.push_back(source_index); 62 | }; 63 | // Sort mapped indices. 64 | sort(mapped_list.begin(), mapped_list.end(), less()); 65 | // Delete bottom rows first so that remaining indices remain correct. 66 | for (QModelIndexList::reverse_iterator i=mapped_list.rbegin(); i!=mapped_list.rend(); i++) { 67 | m_model->delete_category((*i).row()); 68 | }; 69 | }; 70 | } 71 | 72 | void CategoryPicker::rename_category(void) { 73 | RenameDialog rename_dialog(this); 74 | rename_dialog.set_model(m_model); 75 | QModelIndex index = m_ui.category_table->currentIndex(); 76 | QModelIndex source_index = m_sort_filter_proxy_model.mapToSource(index); 77 | rename_dialog.set_name(m_model->category(source_index.row())); 78 | if (rename_dialog.exec() == QDialog::Accepted) { 79 | m_model->rename_category(source_index.row(), rename_dialog.name()); 80 | }; 81 | } 82 | 83 | void CategoryPicker::merge_category(void) { 84 | MergeDialog merge_dialog(this); 85 | merge_dialog.set_model(m_model); 86 | QModelIndex index = m_ui.category_table->currentIndex(); 87 | QModelIndex source_index = m_sort_filter_proxy_model.mapToSource(index); 88 | merge_dialog.set_name(m_model->category(source_index.row())); 89 | if (merge_dialog.exec() == QDialog::Accepted) { 90 | if (QMessageBox::question(this, tr("Merge Category"), tr("Do you want to merge the category?")) == QMessageBox::Yes) { 91 | m_model->merge_category(source_index.row(), merge_dialog.name()); 92 | }; 93 | }; 94 | } 95 | -------------------------------------------------------------------------------- /anymeal/database.hh: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2023 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #pragma once 17 | #include 18 | #include 19 | #include 20 | #include "recipe.hh" 21 | 22 | 23 | class database_exception: public std::exception 24 | { 25 | public: 26 | database_exception(const std::string &error): m_error(error) {} 27 | virtual ~database_exception(void) throw() {} 28 | virtual const char *what(void) const throw() { return m_error.c_str(); } 29 | protected: 30 | std::string m_error; 31 | }; 32 | 33 | class Database 34 | { 35 | public: 36 | Database(void); 37 | virtual ~Database(void); 38 | void open(const char *filename); 39 | sqlite3 *db(void) { return m_db; } 40 | void begin(void); 41 | void commit(void); 42 | void rollback(void); 43 | sqlite3_int64 insert_recipe(Recipe &recipe); 44 | int num_recipes(void); 45 | int count_recipes(const char *category); 46 | std::vector > recipe_info(void); 47 | std::vector categories(void); 48 | std::vector > categories_and_counts(void); 49 | void select_all(void); 50 | void select_by_title(const char *title); 51 | void select_by_category(const char *category); 52 | void select_by_no_category(const char *category); 53 | void select_by_ingredient(const char *ingredient); 54 | void select_by_no_ingredient(const char *ingredient); 55 | Recipe fetch_recipe(sqlite3_int64 id); 56 | std::vector fetch_recipes(const std::vector &ids); 57 | void delete_recipes(const std::vector &ids); 58 | void add_recipes_to_category(const std::vector &ids, const char *category); 59 | void remove_recipes_from_category(const std::vector &ids, const char *category); 60 | void rename_category(const char *current_name, const char *new_name); 61 | sqlite3_int64 get_category_id(const char *name); 62 | void add_category(const char *name); 63 | void merge_category(const char *category, const char *target); 64 | void delete_category(const char *category); 65 | void garbage_collect(void); 66 | protected: 67 | void create_version_1(void); 68 | void migrate_version_1_to_version_2(void); 69 | void migrate_version_2_to_version_3(void); 70 | void migrate(void); 71 | void check(int result, const char *prefix); 72 | int user_version(void); 73 | void pragmas(void); 74 | sqlite3 *m_db; 75 | sqlite3_stmt *m_begin; 76 | sqlite3_stmt *m_commit; 77 | sqlite3_stmt *m_rollback; 78 | sqlite3_stmt *m_insert_recipe; 79 | sqlite3_stmt *m_add_category; 80 | sqlite3_stmt *m_recipe_category; 81 | sqlite3_stmt *m_add_ingredient; 82 | sqlite3_stmt *m_recipe_ingredient; 83 | sqlite3_stmt *m_get_header; 84 | sqlite3_stmt *m_get_categories; 85 | sqlite3_stmt *m_category_and_count_list; 86 | sqlite3_stmt *m_get_ingredients; 87 | sqlite3_stmt *m_add_instruction; 88 | sqlite3_stmt *m_get_instructions; 89 | sqlite3_stmt *m_add_ingredient_section; 90 | sqlite3_stmt *m_get_ingredient_section; 91 | sqlite3_stmt *m_add_instruction_section; 92 | sqlite3_stmt *m_get_instruction_section; 93 | sqlite3_stmt *m_count_selected; 94 | sqlite3_stmt *m_get_info; 95 | sqlite3_stmt *m_select_title; 96 | sqlite3_stmt *m_category_list; 97 | sqlite3_stmt *m_select_category; 98 | sqlite3_stmt *m_select_no_category; 99 | sqlite3_stmt *m_select_ingredient; 100 | sqlite3_stmt *m_select_no_ingredient; 101 | sqlite3_stmt *m_delete_recipe; 102 | sqlite3_stmt *m_delete_categories; 103 | sqlite3_stmt *m_delete_ingredients; 104 | sqlite3_stmt *m_delete_instructions; 105 | sqlite3_stmt *m_delete_ingredient_sections; 106 | sqlite3_stmt *m_delete_instruction_sections; 107 | sqlite3_stmt *m_delete_selection; 108 | sqlite3_stmt *m_clean_categories; 109 | sqlite3_stmt *m_clean_ingredients; 110 | sqlite3_stmt *m_select_recipe; 111 | sqlite3_stmt *m_remove_recipe_category; 112 | sqlite3_stmt *m_rename_category; 113 | sqlite3_stmt *m_get_category_id; 114 | sqlite3_stmt *m_merge_category; 115 | sqlite3_stmt *m_delete_category; 116 | sqlite3_stmt *m_delete_recipe_category; 117 | sqlite3_stmt *m_count_recipes_in_category; 118 | }; 119 | -------------------------------------------------------------------------------- /anymeal/converter_window.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | ConverterWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 391 10 | 162 11 | 12 | 13 | 14 | Convert Units 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Amo&unt 23 | 24 | 25 | source_amount_spin 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 1 34 | 0 35 | 36 | 37 | 38 | 3 39 | 40 | 41 | 999.999000000000024 42 | 43 | 44 | 1.000000000000000 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 1 59 | 0 60 | 61 | 62 | 63 | 3 64 | 65 | 66 | 0.001000000000000 67 | 68 | 69 | 99.998999999999995 70 | 71 | 72 | 1.000000000000000 73 | 74 | 75 | 76 | 77 | 78 | 79 | kg/l 80 | 81 | 82 | 83 | 84 | 85 | 86 | Con&verted 87 | 88 | 89 | dest_amount_edit 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 1 98 | 0 99 | 100 | 101 | 102 | ? 103 | 104 | 105 | true 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | Qt::Horizontal 118 | 119 | 120 | QDialogButtonBox::Ok 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | buttonBox 130 | accepted() 131 | ConverterWindow 132 | accept() 133 | 134 | 135 | 214 136 | 126 137 | 138 | 139 | 157 140 | 161 141 | 142 | 143 | 144 | 145 | buttonBox 146 | rejected() 147 | ConverterWindow 148 | reject() 149 | 150 | 151 | 282 152 | 132 153 | 154 | 155 | 286 156 | 161 157 | 158 | 159 | 160 | 161 | 162 | -------------------------------------------------------------------------------- /anymeal/instructions_model.cc: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2023 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #include 17 | #include "instructions_model.hh" 18 | 19 | 20 | using namespace std; 21 | 22 | InstructionsModel::InstructionsModel(QObject *parent, vector &instructions, vector > §ions): 23 | QAbstractListModel(parent) 24 | { 25 | for (int i=0; i<=(signed)sections.size(); i++) { 26 | if (i > 0) { 27 | m_sections.push_back(sections[i - 1].second); 28 | }; 29 | int a = i == 0 ? 0 : sections[i - 1].first; 30 | int b = i < (signed)sections.size() ? sections[i].first : instructions.size(); 31 | ostringstream s; 32 | for (int j=a; j 0) 50 | result = QString(m_sections[row - 1].c_str()); 51 | else 52 | result = tr("
"); 53 | }; 54 | return result; 55 | } 56 | 57 | std::string InstructionsModel::get_section(const QModelIndex &index) const { 58 | int row = index.row(); 59 | if (row > 0) 60 | return m_sections[row - 1]; 61 | else 62 | return tr("
").toUtf8().constData(); 63 | } 64 | 65 | void InstructionsModel::set_section(const QModelIndex &index, const char *text) { 66 | int row = index.row(); 67 | if (row > 0) { 68 | m_sections[row - 1] = text; 69 | emit dataChanged(index, index); 70 | }; 71 | } 72 | 73 | QModelIndex InstructionsModel::add_section(const QModelIndex &idx) { 74 | if (!idx.isValid()) 75 | return idx; 76 | int row = idx.row(); 77 | beginInsertRows(QModelIndex(), row + 1, row + 1); 78 | m_sections.insert(m_sections.begin() + row, tr("section").toUtf8().constData()); 79 | m_instructions.insert(m_instructions.begin() + row + 1, ""); 80 | endInsertRows(); 81 | return index(row + 1, 0, QModelIndex()); 82 | } 83 | 84 | QModelIndex InstructionsModel::remove_section(const QModelIndex &idx) { 85 | if (!idx.isValid()) 86 | return idx; 87 | int row = idx.row(); 88 | if (row == 0) 89 | return idx; 90 | beginRemoveRows(QModelIndex(), row, row); 91 | m_sections.erase(m_sections.begin() + row - 1); 92 | m_instructions.erase(m_instructions.begin() + row); 93 | endRemoveRows(); 94 | return index(row - 1, 0, QModelIndex()); 95 | } 96 | 97 | string InstructionsModel::get_text(const QModelIndex &index) const { 98 | if (!index.isValid()) 99 | return ""; 100 | int row = index.row(); 101 | return m_instructions[row]; 102 | } 103 | 104 | void InstructionsModel::set_text(const QModelIndex &index, const char *text) { 105 | if (!index.isValid()) 106 | return; 107 | int row = index.row(); 108 | m_instructions[row] = text; 109 | } 110 | 111 | vector InstructionsModel::get_instructions(void) { 112 | vector result; 113 | for (int i=0; i<(signed)m_instructions.size(); i++) { 114 | string s = m_instructions[i]; 115 | if (!s.empty()) { 116 | size_t pos; 117 | while ((pos = s.find('\n')) != string::npos) { 118 | result.push_back(s.substr(0, pos)); 119 | s = s.substr(pos + 1, s.length() - pos - 1); 120 | }; 121 | result.push_back(s); 122 | } else if (i > 0) { 123 | result.push_back(s); 124 | }; 125 | }; 126 | return result; 127 | } 128 | 129 | vector > InstructionsModel::get_sections(void) { 130 | vector > result; 131 | int offset = 0; 132 | for (int i=0; i<(signed)m_instructions.size(); i++) { 133 | string s = m_instructions[i]; 134 | if (!s.empty()) { 135 | size_t pos = 0; 136 | while ((pos = s.find('\n', pos)) != string::npos) { 137 | pos++; 138 | offset++; 139 | }; 140 | offset++; 141 | } else if (i > 0) { 142 | offset++; 143 | }; 144 | if (i < (signed)m_sections.size()) 145 | result.push_back(pair(offset, m_sections[i])); 146 | }; 147 | return result; 148 | } 149 | 150 | bool InstructionsModel::has_acceptable_input(void) { 151 | for (vector::iterator i=m_sections.begin(); i!=m_sections.end(); i++) { 152 | if (i->empty()) 153 | return false; 154 | }; 155 | return true; 156 | } 157 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [AnyMeal][1] [![Build Status](https://github.com/wedesoft/anymeal/actions/workflows/anymeal.yml/badge.svg)](https://github.com/wedesoft/anymeal/actions/workflows/anymeal.yml) [![Downloads](https://img.shields.io/github/downloads/wedesoft/anymeal/total.svg)](https://github.com/wedesoft/anymeal/releases/latest) [![Donate](https://img.shields.io/badge/donate-The%20Water%20Project-green)](https://thewaterproject.org/) 2 | 3 | AnyMeal is a free and open source recipe management software developed using SQLite3 and Qt6. 4 | It can manage a cookbook with more than 250,000 MealMaster recipes, thereby allowing to import, export, search, display, edit, and print them. 5 | AnyMeal is available for GNU/Linux and Microsoft Windows. 6 | 7 | For Mealmaster recipes to download see: 8 | * https://wedesoft.github.io/anymeal/ 9 | 10 | ## Install from source 11 | ### Install latest release on Debian based distribution 12 | 13 | Download the \*.tar.xz file of the [latest release][2]. 14 | You can then install the software under GNU/Linux as follows: 15 | 16 | ```Shell 17 | tar xJf anymeal-*.tar.xz 18 | cd anymeal-*/ 19 | sudo apt-get install build-essential autoconf libtool flex googletest libsqlite3-dev qt6-base-dev-tools qt6-tools-dev-tools qt6-base-dev qt6-svg-dev 20 | ./configure --prefix=/usr 21 | make clean 22 | make all 23 | sudo make install 24 | cd .. 25 | ``` 26 | 27 | You can then run anymeal: 28 | 29 | ```Shell 30 | anymeal 31 | ``` 32 | 33 | ### Install current software from Git repository (Debian based) 34 | 35 | Installation from Git repository requires additional installation of autoconf and creation of the configure script: 36 | 37 | ```Shell 38 | git clone https://github.com/wedesoft/anymeal.git 39 | cd anymeal 40 | sudo apt-get install build-essential autoconf libtool flex googletest libsqlite3-dev qt6-base-dev-tools qt6-tools-dev-tools qt6-base-dev qt6-svg-dev 41 | sh ./autogen.sh 42 | ./configure --prefix=/usr 43 | make clean 44 | make all 45 | sudo make install 46 | cd .. 47 | ``` 48 | 49 | ### Deinstallation 50 | 51 | ``` 52 | cd anymeal*/ 53 | sudo make uninstall 54 | cd .. 55 | ``` 56 | 57 | The database can be removed as follows: 58 | 59 | ``` 60 | rm $HOME/.local/share/anymeal/anymeal.sqlite 61 | ``` 62 | 63 | ## Install on GNU/Linux using AppImage 64 | ### Installation 65 | 66 | Download the \*.AppImage file of the [latest release][2]. 67 | After downloading you just need to make the software executable: 68 | Right-click on AppImage file, open preferences, and enable executable permission. 69 | 70 | You can then run anymeal by left-clicking on the AppImage file. 71 | 72 | ### Deinstallation 73 | 74 | Simply delete the app image. 75 | 76 | The database can be removed by navigating to /home/\/.local/share/anymeal and then deleting the anymeal.sqlite file. 77 | 78 | ## Install on GNU/Linux using Snap 79 | ### Installation 80 | 81 | ``` 82 | sudo snap install anymeal 83 | ``` 84 | 85 | ### Deinstallation 86 | 87 | ``` 88 | sudo snap remove anymeal 89 | ``` 90 | 91 | To remove the database as well, do this instead: 92 | ``` 93 | sudo snap remove --purge anymeal 94 | ``` 95 | 96 | ## Use installer for Microsoft Windows 97 | ### Installation 98 | 99 | Download and run the \*.exe installer of the [latest release][2]. 100 | By default the installer will create a Start Menu shortcut and a desktop shortcut. 101 | 102 | ### Deinstallation 103 | 104 | Open the Control Panel and select the applet for Programs and Features. 105 | Select AnyMeal, then right-click and select Uninstall to remove the program. 106 | 107 | To remove the database open the file explorer and open C:\\Users\\\\\AppData\\Roaming\\anymeal. 108 | Then select the anymeal.sqlite file, right-click, and choose Delete from the pop-up menu. 109 | 110 | ## Packaging status 111 | 112 | [![Packaging status](https://repology.org/badge/vertical-allrepos/anymeal.svg)](https://repology.org/project/anymeal/versions) 113 | 114 | ## AnyMeal Links 115 | 116 | * [Github](https://github.com/wedesoft/anymeal) 117 | * [Bitbucket](https://bitbucket.org/wedesoft/anymeal/) 118 | * [Gitlab](https://gitlab.com/wedesoft/anymeal) 119 | * [Snap package](https://snapcraft.io/anymeal) 120 | * [Sourceforge](https://sourceforge.net/projects/anymeal/) 121 | * [KDE Store](https://store.kde.org/p/1126368/) 122 | * [GNOME Look](https://www.gnome-look.org/p/1126368) 123 | * [Linux Apps](https://www.linux-apps.com/p/1126368) 124 | * [Pling](https://www.pling.com/p/1126368/) 125 | * [FSF Directory](https://directory.fsf.org/wiki/Anymeal) 126 | * [Hackernews](https://news.ycombinator.com/item?id=23738543) 127 | * [Fedora Linux](https://packages.fedoraproject.org/pkgs/anymeal/) 128 | * [AlternativeTo](https://alternativeto.net/software/anymeal/) 129 | * [Softpedia](https://www.softpedia.com/get/Others/Home-Education/AnyMeal.shtml) 130 | * [CNET Download](https://download.cnet.com/AnyMeal/3000-2126_4-78617151.html) 131 | * [Debian Package Tracker](https://tracker.debian.org/pkg/anymeal) 132 | * [Archlinux user repository page](https://aur.archlinux.org/packages/anymeal/) 133 | * [Repology](https://repology.org/project/anymeal/versions) 134 | * [POPCON](https://qa.debian.org/popcon.php?package=anymeal) 135 | 136 | [1]: https://wedesoft.github.io/anymeal/ 137 | [2]: https://github.com/wedesoft/anymeal/releases/latest 138 | -------------------------------------------------------------------------------- /anymeal/category_table_model.cc: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2025 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #include "category_table_model.hh" 17 | 18 | using namespace std; 19 | 20 | CategoryTableModel::CategoryTableModel(QObject *parent, Database *database): 21 | QAbstractTableModel(parent), m_database(database) 22 | { 23 | } 24 | 25 | void CategoryTableModel::reset(const set &selection) { 26 | beginResetModel(); 27 | m_categories_and_counts = m_database->categories_and_counts(); 28 | m_selection = selection; 29 | endResetModel(); 30 | } 31 | 32 | int CategoryTableModel::rowCount(const QModelIndex &) const { 33 | return m_categories_and_counts.size(); 34 | } 35 | 36 | int CategoryTableModel::columnCount(const QModelIndex &) const { 37 | return 2; 38 | } 39 | 40 | QVariant CategoryTableModel::headerData(int section, Qt::Orientation orientation, int role) const 41 | { 42 | if (role == Qt::DisplayRole) { 43 | if (orientation == Qt::Horizontal) { 44 | switch (section) { 45 | case 0: 46 | return QVariant(tr("Category")); 47 | case 1: 48 | return QVariant(tr("# Recipes")); 49 | }; 50 | } else 51 | return section; 52 | }; 53 | return QVariant(); 54 | } 55 | 56 | QVariant CategoryTableModel::data(const QModelIndex &index, int role) const { 57 | QVariant result; 58 | int row = index.row(); 59 | int column = index.column(); 60 | if (role == Qt::DisplayRole || role == Qt::EditRole) { 61 | switch (column) { 62 | case 0: 63 | result = QString(m_categories_and_counts[row].first.c_str()); 64 | break; 65 | case 1: 66 | result = m_categories_and_counts[row].second; 67 | break; 68 | }; 69 | } else if (role == Qt::CheckStateRole && column == 0) { 70 | string category = m_categories_and_counts[row].first; 71 | result = m_selection.find(category) != m_selection.end() ? Qt::Checked : Qt::Unchecked; 72 | }; 73 | return result; 74 | } 75 | 76 | bool CategoryTableModel::setData(const QModelIndex &index, const QVariant &value, int role) { 77 | if (role == Qt::CheckStateRole && index.column() == 0) { 78 | string category = m_categories_and_counts[index.row()].first; 79 | if (value == Qt::Checked) 80 | m_selection.insert(category); 81 | else 82 | m_selection.erase(category); 83 | }; 84 | return true; 85 | } 86 | 87 | Qt::ItemFlags CategoryTableModel::flags(const QModelIndex &index) const { 88 | int column = index.column(); 89 | Qt::ItemFlags f = QAbstractTableModel::flags(index); 90 | if (column == 0) 91 | f |= Qt::ItemIsUserCheckable; 92 | return f; 93 | } 94 | 95 | QModelIndex CategoryTableModel::add_category(const string &name) { 96 | int row = m_categories_and_counts.size(); 97 | beginInsertRows(QModelIndex(), row, row); 98 | m_categories_and_counts.push_back(make_pair(name, 0)); 99 | m_database->add_category(name.c_str()); 100 | endInsertRows(); 101 | return createIndex(row, 0); 102 | } 103 | 104 | void CategoryTableModel::delete_category(int row) { 105 | beginRemoveRows(QModelIndex(), row, row); 106 | string category = m_categories_and_counts[row].first; 107 | m_categories_and_counts.erase(m_categories_and_counts.begin() + row); 108 | set::iterator i = m_selection.find(category); 109 | if (i!=m_selection.end()) { 110 | m_selection.erase(i); 111 | }; 112 | m_database->delete_category(category.c_str()); 113 | endRemoveRows(); 114 | } 115 | 116 | void CategoryTableModel::rename_category(int row, const string &name) { 117 | QModelIndex index = createIndex(row, 0); 118 | string current_name = m_categories_and_counts[row].first; 119 | m_categories_and_counts[row].first = name; 120 | m_database->rename_category(current_name.c_str(), name.c_str()); 121 | set::iterator i = m_selection.find(current_name); 122 | if (i!=m_selection.end()) { 123 | m_selection.erase(i); 124 | }; 125 | emit dataChanged(index, index); 126 | } 127 | 128 | void CategoryTableModel::merge_category(int row, const std::string &name) { 129 | beginRemoveRows(QModelIndex(), row, row); 130 | string current_name = m_categories_and_counts[row].first; 131 | m_database->merge_category(current_name.c_str(), name.c_str()); 132 | m_categories_and_counts.erase(m_categories_and_counts.begin() + row); 133 | set::iterator i = m_selection.find(current_name); 134 | if (i!=m_selection.end()) { 135 | m_selection.erase(i); 136 | m_selection.insert(name); 137 | }; 138 | endRemoveRows(); 139 | for (unsigned int i=0; icount_recipes(name.c_str()); 142 | QModelIndex index = createIndex(i, 0); 143 | emit dataChanged(index, index.siblingAtColumn(1)); 144 | break; 145 | }; 146 | }; 147 | } 148 | -------------------------------------------------------------------------------- /anymeal/duplicate.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 18 | 37 | 41 | 48 | 52 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /m4/ax_lib_sqlite3.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # https://www.gnu.org/software/autoconf-archive/ax_lib_sqlite3.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_LIB_SQLITE3([MINIMUM-VERSION]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # Test for the SQLite 3 library of a particular version (or newer) 12 | # 13 | # This macro takes only one optional argument, required version of SQLite 14 | # 3 library. If required version is not passed, 3.0.0 is used in the test 15 | # of existence of SQLite 3. 16 | # 17 | # If no installation prefix to the installed SQLite library is given the 18 | # macro searches under /usr, /usr/local, and /opt. 19 | # 20 | # This macro calls: 21 | # 22 | # AC_SUBST(SQLITE3_CFLAGS) 23 | # AC_SUBST(SQLITE3_LDFLAGS) 24 | # AC_SUBST(SQLITE3_VERSION) 25 | # 26 | # And sets: 27 | # 28 | # HAVE_SQLITE3 29 | # 30 | # LICENSE 31 | # 32 | # Copyright (c) 2008 Mateusz Loskot 33 | # 34 | # Copying and distribution of this file, with or without modification, are 35 | # permitted in any medium without royalty provided the copyright notice 36 | # and this notice are preserved. This file is offered as-is, without any 37 | # warranty. 38 | 39 | #serial 18 40 | 41 | AC_DEFUN([AX_LIB_SQLITE3], 42 | [ 43 | AC_ARG_WITH([sqlite3], 44 | AS_HELP_STRING( 45 | [--with-sqlite3=@<:@ARG@:>@], 46 | [use SQLite 3 library @<:@default=yes@:>@, optionally specify the prefix for sqlite3 library] 47 | ), 48 | [ 49 | if test "$withval" = "no"; then 50 | WANT_SQLITE3="no" 51 | elif test "$withval" = "yes"; then 52 | WANT_SQLITE3="yes" 53 | ac_sqlite3_path="" 54 | else 55 | WANT_SQLITE3="yes" 56 | ac_sqlite3_path="$withval" 57 | fi 58 | ], 59 | [WANT_SQLITE3="yes"] 60 | ) 61 | 62 | SQLITE3_CFLAGS="" 63 | SQLITE3_LDFLAGS="" 64 | SQLITE3_VERSION="" 65 | 66 | if test "x$WANT_SQLITE3" = "xyes"; then 67 | 68 | ac_sqlite3_header="sqlite3.h" 69 | 70 | sqlite3_version_req=ifelse([$1], [], [3.0.0], [$1]) 71 | sqlite3_version_req_shorten=`expr $sqlite3_version_req : '\([[0-9]]*\.[[0-9]]*\)'` 72 | sqlite3_version_req_major=`expr $sqlite3_version_req : '\([[0-9]]*\)'` 73 | sqlite3_version_req_minor=`expr $sqlite3_version_req : '[[0-9]]*\.\([[0-9]]*\)'` 74 | sqlite3_version_req_micro=`expr $sqlite3_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'` 75 | if test "x$sqlite3_version_req_micro" = "x" ; then 76 | sqlite3_version_req_micro="0" 77 | fi 78 | 79 | sqlite3_version_req_number=`expr $sqlite3_version_req_major \* 1000000 \ 80 | \+ $sqlite3_version_req_minor \* 1000 \ 81 | \+ $sqlite3_version_req_micro` 82 | 83 | AC_MSG_CHECKING([for SQLite3 library >= $sqlite3_version_req]) 84 | 85 | if test "$ac_sqlite3_path" != ""; then 86 | ac_sqlite3_ldflags="-L$ac_sqlite3_path/lib" 87 | ac_sqlite3_cppflags="-I$ac_sqlite3_path/include" 88 | else 89 | for ac_sqlite3_path_tmp in /usr /usr/local /opt ; do 90 | if test -f "$ac_sqlite3_path_tmp/include/$ac_sqlite3_header" \ 91 | && test -r "$ac_sqlite3_path_tmp/include/$ac_sqlite3_header"; then 92 | ac_sqlite3_path=$ac_sqlite3_path_tmp 93 | ac_sqlite3_cppflags="-I$ac_sqlite3_path_tmp/include" 94 | ac_sqlite3_ldflags="-L$ac_sqlite3_path_tmp/lib" 95 | break; 96 | fi 97 | done 98 | fi 99 | 100 | ac_sqlite3_ldflags="$ac_sqlite3_ldflags -lsqlite3" 101 | 102 | saved_CPPFLAGS="$CPPFLAGS" 103 | CPPFLAGS="$CPPFLAGS $ac_sqlite3_cppflags" 104 | 105 | AC_LANG_PUSH(C) 106 | AC_COMPILE_IFELSE( 107 | [ 108 | AC_LANG_PROGRAM([[@%:@include ]], 109 | [[ 110 | #if (SQLITE_VERSION_NUMBER >= $sqlite3_version_req_number) 111 | /* Everything is okay */ 112 | #else 113 | # error SQLite version is too old 114 | #endif 115 | ]] 116 | ) 117 | ], 118 | [ 119 | AC_MSG_RESULT([yes]) 120 | success="yes" 121 | ], 122 | [ 123 | AC_MSG_RESULT([not found]) 124 | success="no" 125 | ] 126 | ) 127 | AC_LANG_POP(C) 128 | 129 | CPPFLAGS="$saved_CPPFLAGS" 130 | 131 | if test "$success" = "yes"; then 132 | 133 | SQLITE3_CFLAGS="$ac_sqlite3_cppflags" 134 | SQLITE3_LDFLAGS="$ac_sqlite3_ldflags" 135 | 136 | ac_sqlite3_header_path="$ac_sqlite3_path/include/$ac_sqlite3_header" 137 | 138 | dnl Retrieve SQLite release version 139 | if test "x$ac_sqlite3_header_path" != "x"; then 140 | ac_sqlite3_version=`cat $ac_sqlite3_header_path \ 141 | | grep '#define.*SQLITE_VERSION.*\"' | sed -e 's/.* "//' \ 142 | | sed -e 's/"//'` 143 | if test $ac_sqlite3_version != ""; then 144 | SQLITE3_VERSION=$ac_sqlite3_version 145 | else 146 | AC_MSG_WARN([Cannot find SQLITE_VERSION macro in sqlite3.h header to retrieve SQLite version!]) 147 | fi 148 | fi 149 | 150 | AC_SUBST(SQLITE3_CFLAGS) 151 | AC_SUBST(SQLITE3_LDFLAGS) 152 | AC_SUBST(SQLITE3_VERSION) 153 | AC_DEFINE([HAVE_SQLITE3], [], [Have the SQLITE3 library]) 154 | fi 155 | fi 156 | ]) 157 | -------------------------------------------------------------------------------- /anymeal/export_dialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | ExportDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 410 10 | 136 11 | 12 | 13 | 14 | Export MealMaster Recipes 15 | 16 | 17 | 18 | :/images/export.svg:/images/export.svg 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | En&coding 27 | 28 | 29 | encoding_combo 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 1 38 | 0 39 | 40 | 41 | 42 | true 43 | 44 | 45 | 46 | ISO-8859-1 47 | 48 | 49 | 50 | 51 | ISO-8859-15 52 | 53 | 54 | 55 | 56 | CP850 57 | 58 | 59 | 60 | 61 | UTF-8 62 | 63 | 64 | 65 | 66 | US-ASCII 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | Error Fi&le 75 | 76 | 77 | error_file_edit 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 1 88 | 0 89 | 90 | 91 | 92 | /tmp/errors.mmf 93 | 94 | 95 | true 96 | 97 | 98 | 99 | 100 | 101 | 102 | &Select error file 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | Qt::Vertical 114 | 115 | 116 | 117 | 20 118 | 3 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | Qt::Horizontal 129 | 130 | 131 | 132 | 40 133 | 20 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | Proceed with selection of output file 142 | 143 | 144 | 145 | 146 | 147 | 148 | &Cancel 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | proceed_button 162 | clicked() 163 | ExportDialog 164 | accept() 165 | 166 | 167 | 77 168 | 66 169 | 170 | 171 | 35 172 | 68 173 | 174 | 175 | 176 | 177 | cancel_button 178 | clicked() 179 | ExportDialog 180 | reject() 181 | 182 | 183 | 315 184 | 62 185 | 186 | 187 | 364 188 | 89 189 | 190 | 191 | 192 | 193 | 194 | -------------------------------------------------------------------------------- /anymeal/import_dialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | ImportDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 373 10 | 136 11 | 12 | 13 | 14 | Import MealMaster Recipes 15 | 16 | 17 | 18 | :/images/import.svg:/images/import.svg 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | Encodin&g 27 | 28 | 29 | encoding_combo 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 1 38 | 0 39 | 40 | 41 | 42 | true 43 | 44 | 45 | 46 | ISO-8859-1 47 | 48 | 49 | 50 | 51 | ISO-8859-15 52 | 53 | 54 | 55 | 56 | CP850 57 | 58 | 59 | 60 | 61 | UTF-8 62 | 63 | 64 | 65 | 66 | US-ASCII 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | Error Fi&le 75 | 76 | 77 | error_file_edit 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 1 88 | 0 89 | 90 | 91 | 92 | /tmp/errors.mmf 93 | 94 | 95 | true 96 | 97 | 98 | 99 | 100 | 101 | 102 | &Select error file 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | Qt::Vertical 114 | 115 | 116 | 117 | 20 118 | 2 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | Qt::Horizontal 129 | 130 | 131 | 132 | 40 133 | 20 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | Pr&oceed with selection of recipes 142 | 143 | 144 | 145 | 146 | 147 | 148 | &Cancel 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | encoding_combo 158 | error_file_edit 159 | browse_button 160 | proceed_button 161 | cancel_button 162 | 163 | 164 | 165 | 166 | 167 | 168 | proceed_button 169 | clicked() 170 | ImportDialog 171 | accept() 172 | 173 | 174 | 107 175 | 118 176 | 177 | 178 | 66 179 | 112 180 | 181 | 182 | 183 | 184 | cancel_button 185 | clicked() 186 | ImportDialog 187 | reject() 188 | 189 | 190 | 365 191 | 123 192 | 193 | 194 | 312 195 | 113 196 | 197 | 198 | 199 | 200 | 201 | -------------------------------------------------------------------------------- /anymeal/export.cc: -------------------------------------------------------------------------------- 1 | /* AnyMeal recipe management software 2 | Copyright (C) 2020, 2023 Jan Wedekind 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . */ 16 | #include 17 | #include "export.hh" 18 | 19 | 20 | using namespace std; 21 | 22 | string recipe_to_mealmaster(Recipe &recipe) { 23 | ostringstream result; 24 | // Output recipe header. 25 | result << "MMMMM----------------Meal-Master recipe exported by AnyMeal-----------------\r\n" 26 | << "\r\n" 27 | << " Title: " << recipe.title() << "\r\n" 28 | << " Categories: "; 29 | set::iterator category = recipe.categories().begin(); 30 | while (category != recipe.categories().end()) { 31 | result << *category++; 32 | if (category != recipe.categories().end()) 33 | result << ", "; 34 | else 35 | break; 36 | }; 37 | result << "\r\n" 38 | << " Yield: " << recipe.servings() << " " << recipe.servings_unit() << "\r\n" 39 | << "\r\n"; 40 | if (!recipe.ingredients().empty()) { 41 | // Output ingredients. 42 | vector > sections = recipe.ingredient_sections(); 43 | vector >::iterator section = sections.begin(); 44 | for (int i=0; ifirst == i) { 46 | // Output an ingredient section. 47 | int n = 71 - section->second.length(); 48 | result << "MMMMM" << string(n / 2, '-') << section->second << string((n + 1) / 2, '-') << "\r\n"; 49 | section++; 50 | }; 51 | Ingredient ingredient = recipe.ingredients()[i]; 52 | string amount; 53 | if (ingredient.amount_float() > 0) { 54 | ostringstream s; 55 | s << ingredient.amount_float(); 56 | amount = s.str(); 57 | } else if (ingredient.amount_integer() > 0) { 58 | ostringstream s; 59 | s << ingredient.amount_integer(); 60 | if (ingredient.amount_numerator() > 0) { 61 | s << " " << ingredient.amount_numerator() << "/" << ingredient.amount_denominator(); 62 | }; 63 | amount = s.str(); 64 | } else if (ingredient.amount_numerator() > 0) { 65 | ostringstream s; 66 | s << ingredient.amount_numerator() << "/" << ingredient.amount_denominator(); 67 | amount = s.str(); 68 | }; 69 | amount = amount.substr(0, 7); 70 | result << string(7 - amount.length(), ' ') << amount; 71 | result << " "; 72 | if (ingredient.unit().empty()) { 73 | result << " "; 74 | } else { 75 | result << ingredient.unit(); 76 | }; 77 | result << " "; 78 | string txt = ingredient.text(); 79 | // Break up ingredient text using continuation lines if necessary. 80 | while (!txt.empty()) { 81 | if (txt.length() <= 28) { 82 | result << txt << "\r\n"; 83 | txt = ""; 84 | } else { 85 | int offset; 86 | // break at space character. 87 | size_t pos = txt.rfind(" ", 28); 88 | if (pos == string::npos) { 89 | // emergency line break if no space character found. 90 | pos = 28; 91 | // ensure potential UTF8 sequences are not broken up. 92 | while (pos > 1 && (txt.at(pos) & 0xC0) == 0x80) 93 | pos--; 94 | offset = 0; 95 | } else 96 | offset = 1; 97 | result << txt.substr(0, pos) << "\r\n" 98 | << " -"; 99 | txt = txt.substr(pos + offset, txt.length() - pos - offset); 100 | }; 101 | }; 102 | if (section != sections.end() && section->first == i + 1) { 103 | // Newline before next ingredient section. 104 | result << "\r\n"; 105 | }; 106 | }; 107 | result << "\r\n"; 108 | }; 109 | if (!recipe.instructions().empty()) { 110 | bool force_newline = false; 111 | // Output recipe instructions. 112 | vector > sections = recipe.instruction_sections(); 113 | vector >::iterator section = sections.begin(); 114 | for (int i=0; ifirst == i) { 116 | // Output an instruction section. 117 | int n = 71 - section->second.length(); 118 | result << "MMMMM" << string(n / 2, '-') << section->second << string((n + 1) / 2, '-') << "\r\n"; 119 | force_newline = false; 120 | section++; 121 | }; 122 | string txt = recipe.instructions()[i]; 123 | if (txt.empty()) { 124 | result << "\r\n"; 125 | force_newline = false; 126 | } else { 127 | while (!txt.empty()) { 128 | int text_width = force_newline ? 74 : 75; 129 | if (txt.length() <= text_width) { 130 | result << " " << (force_newline ? ":" : "") << txt << "\r\n"; 131 | txt = ""; 132 | } else { 133 | // break at space character. 134 | int offset; 135 | size_t pos = txt.rfind(" ", text_width); 136 | if (pos == string::npos) { 137 | // emergency line break if no space character found. 138 | pos = text_width; 139 | // ensure potential UTF8 sequences are not broken up. 140 | while (pos > 1 && (txt.at(pos) & 0xC0) == 0x80) 141 | pos--; 142 | offset = 0; 143 | } else 144 | offset = 1; 145 | result << " " << (force_newline ? ":" : "") << txt.substr(0, pos) << "\r\n"; 146 | txt = txt.substr(pos + offset, txt.length() - pos - offset); 147 | }; 148 | force_newline = false; 149 | }; 150 | force_newline = true; 151 | }; 152 | if (section != sections.end() && section->first == i + 1) { 153 | // Newline before next instruction section. 154 | result << "\r\n"; 155 | }; 156 | }; 157 | result << "\r\n"; 158 | }; 159 | result << "MMMMM"; 160 | return result.str(); 161 | } 162 | -------------------------------------------------------------------------------- /anymeal.nsi: -------------------------------------------------------------------------------- 1 | !include "MUI2.nsh" 2 | 3 | ; The name of the installer 4 | Name "AnyMeal" 5 | 6 | SetCompressor lzma 7 | SetCompress force 8 | 9 | ; The file to write 10 | OutFile "anymeal-installer-1.34.exe" 11 | 12 | ; The default installation directory 13 | InstallDir $PROGRAMFILES\AnyMeal 14 | 15 | ; Registry key to check for directory (so if you install again, it will 16 | ; overwrite the old one automatically) 17 | InstallDirRegKey HKLM "Software\NSIS_AnyMeal" "Install_Dir" 18 | 19 | ;-------------------------------- 20 | 21 | ; Pages 22 | 23 | !define MUI_ICON "anymeal\anymeal.ico" 24 | !define MUI_HEADERIMAGE 25 | !define MUI_HEADERIMAGE_BITMAP "anymeal\header.bmp" 26 | !define MUI_WELCOMEPAGE_TITLE "AnyMeal" 27 | !define MUI_COMPONENTSPAGE_NODESC 28 | 29 | !insertmacro MUI_PAGE_COMPONENTS 30 | !insertmacro MUI_PAGE_DIRECTORY 31 | !insertmacro MUI_PAGE_INSTFILES 32 | 33 | !insertmacro MUI_UNPAGE_CONFIRM 34 | !insertmacro MUI_UNPAGE_INSTFILES 35 | 36 | !insertmacro MUI_LANGUAGE "English" 37 | 38 | ;-------------------------------- 39 | 40 | ; The stuff to install 41 | Section "AnyMeal (required)" 42 | 43 | SectionIn RO 44 | 45 | ; Set output path to the installation directory. 46 | SetOutPath $INSTDIR 47 | 48 | ; Put file there 49 | File "anymeal\.libs\anymeal.exe" 50 | File "anymeal\anymeal.ico" 51 | File "LICENSE" 52 | File "C:\msys64\mingw64\bin\libbrotlicommon.dll" 53 | File "C:\msys64\mingw64\bin\libbrotlidec.dll" 54 | File "C:\msys64\mingw64\bin\libbz2-1.dll" 55 | File "C:\msys64\mingw64\bin\libdouble-conversion.dll" 56 | File "C:\msys64\mingw64\bin\libfreetype-6.dll" 57 | File "C:\msys64\mingw64\bin\libgcc_s_seh-1.dll" 58 | File "C:\msys64\mingw64\bin\libglib-2.0-0.dll" 59 | File "C:\msys64\mingw64\bin\libgraphite2.dll" 60 | File "C:\msys64\mingw64\bin\libharfbuzz-0.dll" 61 | File "C:\msys64\mingw64\bin\libiconv-2.dll" 62 | File "C:\msys64\mingw64\bin\libicudt*.dll" 63 | File "C:\msys64\mingw64\bin\libicuin*.dll" 64 | File "C:\msys64\mingw64\bin\libicuuc*.dll" 65 | File "C:\msys64\mingw64\bin\libintl-8.dll" 66 | File "C:\msys64\mingw64\bin\libmd4c.dll" 67 | File "C:\msys64\mingw64\bin\libpcre-1.dll" 68 | File "C:\msys64\mingw64\bin\libpcre2-8-0.dll" 69 | File "C:\msys64\mingw64\bin\libpcre2-16-0.dll" 70 | File "C:\msys64\mingw64\bin\libb2-1.dll" 71 | File "C:\msys64\mingw64\bin\libpng16-16.dll" 72 | File "C:\msys64\mingw64\bin\libsqlite3-0.dll" 73 | File "C:\msys64\mingw64\bin\libstdc++-6.dll" 74 | File "C:\msys64\mingw64\bin\libwinpthread-1.dll" 75 | File "C:\msys64\mingw64\bin\libzstd.dll" 76 | File "C:\msys64\mingw64\bin\Qt6Core.dll" 77 | File "C:\msys64\mingw64\bin\Qt6Gui.dll" 78 | File "C:\msys64\mingw64\bin\Qt6Svg.dll" 79 | File "C:\msys64\mingw64\bin\Qt6PrintSupport.dll" 80 | File "C:\msys64\mingw64\bin\Qt6Widgets.dll" 81 | File "C:\msys64\mingw64\bin\zlib1.dll" 82 | 83 | SetOutPath "$INSTDIR\platforms" 84 | File "C:\msys64\mingw64\share\qt6\plugins\platforms\qwindows.dll" 85 | 86 | SetOutPath "$INSTDIR\imageformats" 87 | File "C:\msys64\mingw64\share\qt6\plugins\imageformats\qsvg.dll" 88 | 89 | SetOutPath "$INSTDIR\styles" 90 | File "C:\msys64\mingw64\share\qt6\plugins\styles\qmodernwindowsstyle.dll" 91 | 92 | SetOutPath "$INSTDIR\locale\de" 93 | File "anymeal\locale\de\anymeal_qt.qm" 94 | SetOutPath "$INSTDIR\locale\fr" 95 | File "anymeal\locale\fr\anymeal_qt.qm" 96 | SetOutPath "$INSTDIR\locale\nl" 97 | File "anymeal\locale\nl\anymeal_qt.qm" 98 | SetOutPath "$INSTDIR\locale\it" 99 | File "anymeal\locale\it\anymeal_qt.qm" 100 | SetOutPath "$INSTDIR\locale\sl" 101 | File "anymeal\locale\sl\anymeal_qt.qm" 102 | 103 | SetOutPath $INSTDIR 104 | 105 | ; Write the installation path into the registry 106 | WriteRegStr HKLM "SOFTWARE\NSIS_AnyMeal" "Install_Dir" "$INSTDIR" 107 | 108 | ; Write the uninstall keys for Windows 109 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AnyMeal" "DisplayName" "AnyMeal" 110 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AnyMeal" "DisplayIcon" '"$INSTDIR\anymeal.ico"' 111 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AnyMeal" "UninstallString" '"$INSTDIR\uninstall.exe"' 112 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AnyMeal" "Publisher" "Jan Wedekind" 113 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AnyMeal" "DisplayVersion" "1.34" 114 | WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AnyMeal" "EstimatedSize" 76099 115 | WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AnyMeal" "NoModify" 1 116 | WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AnyMeal" "NoRepair" 1 117 | WriteUninstaller "uninstall.exe" 118 | 119 | SectionEnd 120 | 121 | ; Optional section (can be disabled by the user) 122 | Section "Start Menu Shortcuts" 123 | 124 | CreateDirectory "$SMPROGRAMS\AnyMeal" 125 | CreateShortCut "$SMPROGRAMS\AnyMeal\Uninstall.lnk" "$INSTDIR\uninstall.exe" "" "$INSTDIR\uninstall.exe" 0 126 | CreateShortCut "$SMPROGRAMS\AnyMeal\AnyMeal.lnk" "$INSTDIR\anymeal.exe" "" "$INSTDIR\anymeal.exe" 0 127 | 128 | SectionEnd 129 | 130 | Section "Desktop Shortcut" 131 | CreateShortCut "$DESKTOP\AnyMeal.lnk" "$INSTDIR\anymeal.exe" "" "$INSTDIR\anymeal.exe" 0 132 | SectionEnd 133 | 134 | ;-------------------------------- 135 | 136 | ; Uninstaller 137 | 138 | Section "Uninstall" 139 | 140 | ; Remove registry keys 141 | DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AnyMeal" 142 | DeleteRegKey HKLM "SOFTWARE\NSIS_AnyMeal" 143 | 144 | ; Remove files and uninstaller 145 | Delete "$INSTDIR\styles\*.dll" 146 | Delete "$INSTDIR\imageformats\*.dll" 147 | Delete "$INSTDIR\platforms\*.dll" 148 | Delete "$INSTDIR\locale\sl\*.qm" 149 | Delete "$INSTDIR\locale\it\*.qm" 150 | Delete "$INSTDIR\locale\nl\*.qm" 151 | Delete "$INSTDIR\locale\de\*.qm" 152 | Delete "$INSTDIR\locale\fr\*.qm" 153 | Delete "$INSTDIR\*.dll" 154 | Delete $INSTDIR\LICENSE 155 | Delete $INSTDIR\anymeal.exe 156 | Delete $INSTDIR\anymeal.ico 157 | Delete $INSTDIR\uninstall.exe 158 | 159 | ; Remove shortcuts, if any 160 | Delete "$SMPROGRAMS\AnyMeal\*.*" 161 | Delete "$DESKTOP\AnyMeal.lnk" 162 | 163 | ; Remove directories used 164 | RMDir "$SMPROGRAMS\AnyMeal" 165 | RMDir "$INSTDIR\locale\sl" 166 | RMDir "$INSTDIR\locale\it" 167 | RMDir "$INSTDIR\locale\nl" 168 | RMDir "$INSTDIR\locale\de" 169 | RMDir "$INSTDIR\locale\fr" 170 | RMDir "$INSTDIR\locale" 171 | RMDir "$INSTDIR\styles" 172 | RMDir "$INSTDIR\imageformats" 173 | RMDir "$INSTDIR\platforms" 174 | RMDir "$INSTDIR" 175 | 176 | SectionEnd 177 | --------------------------------------------------------------------------------