Migration to View/Model design (#195)

Squashed commit of the following:

commit 7929b8f0f6ec21ae0fb90203205e4224ce5bc1b7
Author: donoban <donoban@riseup.net>
Date:   Tue Jul 28 17:21:11 2020 +0200

    Try to fix sort

commit 5e4598e1d6aba0e2208e7bca761be83931457a26
Author: donoban <donoban@riseup.net>
Date:   Mon Jul 27 04:06:37 2020 +0200

    Fix import

commit 60f53e7ef0e35fde9143835b18015db570739544
Author: donoban <donoban@riseup.net>
Date:   Mon Jul 27 04:03:17 2020 +0200

    Fix 218 test

commit e430e394774bba4ca306f2fb0b8d55e10f9e2bc2
Author: donoban <donoban@riseup.net>
Date:   Mon Jul 27 04:01:56 2020 +0200

    Avoid error if dvm is None

commit 679880ff4f3d7117784e90d6cb53538b7fba4f0d
Author: donoban <donoban@riseup.net>
Date:   Mon Jul 27 03:58:59 2020 +0200

    Fix sorting again

commit f84edcdc02bf311de9d60274ae7fba90566a460e
Author: donoban <donoban@riseup.net>
Date:   Sun Jul 26 03:30:14 2020 +0200

    Yes, it's needed

commit 5d00c91db45f99c78d7f15f77dd65a51b286fc77
Author: donoban <donoban@riseup.net>
Date:   Sat Jul 25 23:08:38 2020 +0200

    Fix pylint error

commit 88a54dc3d2927a04c44e8d4c9548e123852b3e39
Author: donoban <donoban@riseup.net>
Date:   Sat Jul 25 18:56:40 2020 +0200

    Style change

commit 42ae96c45b37e03823e782c67b0995f588c7e0bd
Author: donoban <donoban@riseup.net>
Date:   Sat Jul 25 18:56:00 2020 +0200

    Fix sorting errores

commit daa872297b2082237860a66bb01e2c71fda3e55d
Author: donoban <donoban@riseup.net>
Date:   Sat Jul 25 18:54:21 2020 +0200

    Fixed sort test errors

commit 73ad25ed9e77d25bfc6a4159b8ef9a6f24e3294a
Author: donoban <donoban@riseup.net>
Date:   Sat Jul 25 00:25:37 2020 +0200

    Var rename

commit 825d8ad6f7d3a9a7bb11252ebe5a5402851d56a9
Author: donoban <donoban@riseup.net>
Date:   Fri Jul 24 23:37:04 2020 +0200

    Restored Cleanup

commit 09f183946d23fb4a92e428395834ef3ad4473ffb
Author: donoban <donoban@riseup.net>
Date:   Fri Jul 24 23:35:20 2020 +0200

    Removed workaround, now works properly without clear reason

commit 2f5bde0484e3eb0a3128e8b98f61a5311e0f529e
Author: donoban <donoban@riseup.net>
Date:   Fri Jul 24 23:29:20 2020 +0200

    Multiple tests fixes

commit e21f9ab7416e728d1ef0409fb9ca880e23d9240c
Author: donoban <donoban@riseup.net>
Date:   Fri Jul 24 23:28:32 2020 +0200

    Save dvm name instead VM object

commit 46e2fe1cf68708fa41df59661d11691ddb331984
Author: donoban <donoban@riseup.net>
Date:   Fri Jul 24 01:11:15 2020 +0200

    Deleted wrong mapToSource()

commit b155e051beb4ffcf0c1d48c5c9e24576c7db2e94
Author: donoban <donoban@riseup.net>
Date:   Fri Jul 24 01:10:43 2020 +0200

    Fix get 'Is DVM Template' widget

commit 61d7a6dc05f39055cbfd473c2a5cd638194aa132
Author: donoban <donoban@riseup.net>
Date:   Wed Jul 22 12:17:10 2020 +0200

    fix set_keyboar_layout test fail

commit 1dba52eb14b1d9c190d3a8c7bedf026ba242ac7d
Author: donoban <donoban@riseup.net>
Date:   Sun Jul 19 00:05:53 2020 +0200

    More test fixes

commit 665a1453eca121a3c60975fe4c9e08b05e4831fe
Author: donoban <donoban@riseup.net>
Date:   Sun Jul 12 23:39:07 2020 +0200

    Fixed power state checking

commit 6733fb1cd80cbc0917a5d1e42680d5424364649d
Author: donoban <donoban@riseup.net>
Date:   Sun Jul 12 17:44:01 2020 +0200

    Return vm object instead name on select_vm functions

commit 80f3b3f7498c8c98517ae77053861861aaecfba7
Author: donoban <donoban@riseup.net>
Date:   Sun Jul 12 17:43:27 2020 +0200

    Removed wrong calls to text()

commit 32bbb864bf96ad3e37b6aaddc25817a5ad38a0cc
Author: donoban <donoban@riseup.net>
Date:   Sun Jul 12 17:42:45 2020 +0200

    Removed implicity calls to sortItems()

commit bc288b616b80a5fabe179954eb18953ee59c18bc
Author: donoban <donoban@riseup.net>
Date:   Sun Jul 12 17:03:22 2020 +0200

    setCurrentItem() -> setCurrentIndex()

commit 10bac8d300aa5d428080a0dc6a689e88230d93d2
Author: donoban <donoban@riseup.net>
Date:   Sun Jul 12 16:43:41 2020 +0200

    get_table_vminfo renamed to get_table_vm

commit cee7b0af871183e4917fdb535bbcc83facd64446
Author: donoban <donoban@riseup.net>
Date:   Sat Jul 11 23:46:41 2020 +0200

    First version fixing tests

commit 42d566f032941679608669d1ccc28a4523715b8a
Author: donoban <donoban@riseup.net>
Date:   Sat Jul 11 23:38:33 2020 +0200

    Fixing tests

commit ccd7c162ef2a3f882c7d683d5b9c97db11829ac6
Merge: 24e5d58 8a74e43
Author: donoban <donoban@riseup.net>
Date:   Mon Jun 8 22:16:34 2020 +0200

    Merge branch 'master' of https://github.com/QubesOS/qubes-manager

    # Conflicts:
    #	qubesmanager/qube_manager.py

commit 24e5d58c98981b3635b3c6dfa9202cac3e3455d8
Author: donoban <donoban@riseup.net>
Date:   Sun Jun 7 19:03:09 2020 +0200

    Added workaround for dom0 sorting

commit db2781a6392ff32c2d26053999819e08cb0e0ca0
Author: donoban <donoban@riseup.net>
Date:   Sun Jun 7 18:57:28 2020 +0200

    Fixed Sorting Case Insensivity

commit 93330ea6a45598a212811251843d32682a20016a
Author: donoban <donoban@riseup.net>
Date:   Sun Jun 7 18:51:39 2020 +0200

    Added "default" to netvm and default dispvm

commit a40156c4f4b08a201fb877fc92f547c5138a7e32
Author: donoban <donoban@riseup.net>
Date:   Sun Jun 7 18:18:03 2020 +0200

    Fixed QSettings saving

commit a1d96e78778c84fe077b62196c8ed561978de9bc
Author: donoban <donoban@riseup.net>
Date:   Wed Jun 3 00:23:50 2020 +0200

    Added 'defaultValue' on settings load

commit a0a7ee812298e6361a2ee585049c96303d1bbda7
Author: donoban <donoban@riseup.net>
Date:   Wed Jun 3 00:10:31 2020 +0200

    Init view menu out of load_manager_settings

commit 6f9a60004282e85c32727baa4b49c0a4d080f74e
Author: donoban <donoban@riseup.net>
Date:   Tue Jun 2 23:19:09 2020 +0200

    "Size" renamed to "Disk Usage"

commit 5fbda06b370de790e31a9a983891a69ab8d031de
Author: donoban <donoban@riseup.net>
Date:   Tue Jun 2 01:34:56 2020 +0200

    Replaced unneded elif's with if's

commit 5516bca8616d2e1ab99d4c40b11ff7b69cdbea48
Author: donoban <donoban@riseup.net>
Date:   Tue Jun 2 01:30:46 2020 +0200

    Use "Yes"/"" for bool properties

commit 1e5429e7ef9240570a5f31eae3a49a8380f97ee4
Author: donoban <donoban@riseup.net>
Date:   Tue Jun 2 01:12:46 2020 +0200

    Restored exactly old icon size

commit 270c82547365fbecddab1a21afef637da3eb2aa6
Author: donoban <donoban@riseup.net>
Date:   Sun May 31 12:52:03 2020 +0200

    AdminVM and DispVM icon workaround

commit cfb8a87b6dbdfda6f1652a6a4c82299e60b8c158
Author: donoban <donoban@riseup.net>
Date:   Sun May 31 12:51:44 2020 +0200

    Icon size adjusted to 128/4

commit 173dc9413c6ae81e851026538beb101e385e5974
Author: donoban <donoban@riseup.net>
Date:   Sat May 30 00:56:40 2020 +0200

    Add italic and gray color for differentiate templates and standalone/dom0

commit 2062f9308833241994b3ba87964f4f871b115e2a
Author: donoban <donoban@riseup.net>
Date:   Thu May 28 00:21:58 2020 +0200

    Fixig Marek comments

commit 348485e960d18c5d7fd1746448251374480d270b
Author: donoban <donoban@riseup.net>
Date:   Thu May 28 00:03:44 2020 +0200

    More readable

commit dc823a3923ab6c110fa8c51d4d66e501bc3e9f97
Author: donoban <donoban@riseup.net>
Date:   Thu May 28 00:01:02 2020 +0200

    Needed for pylint proplerly import PyQt5 modules on fedora 32

commit 4478b284ce6f4521d1bddd5f6dc3d564c6c02408
Author: donoban <donoban@riseup.net>
Date:   Tue May 19 01:11:05 2020 +0200

    Removed unused unued vars

commit 450f0e32525792d48f121edfb890f0f24e6f6c36
Author: donoban <donoban@riseup.net>
Date:   Fri May 8 00:26:59 2020 +0200

    Fix wrong var names

commit c1bd9577e21e79a708870bbd22ff557ec0f48547
Author: donoban <donoban@riseup.net>
Date:   Fri May 8 00:24:31 2020 +0200

    Fixed params order to VmSettingsWindow()

commit 6d50d033d5866aa9cd0913822189bf235c8c7bdd
Author: donoban <donoban@riseup.net>
Date:   Fri May 8 00:20:06 2020 +0200

    Modeless settings windows

commit ef3ac6a962b09e34602a624b3e8fdbdaf4cf8a42
Author: donoban <donoban@riseup.net>
Date:   Thu May 7 23:51:30 2020 +0200

    Fix some vm/vm_info confusion

commit 09392f99dc1ecd2e96e756884dd75c22090aa127
Author: donoban <donoban@riseup.net>
Date:   Wed Apr 29 10:26:58 2020 +0200

    removed trailing whitespace

commit 9e35ddf882053b25e2ab1d6cce6393cb77b95e79
Author: donoban <donoban@riseup.net>
Date:   Wed Apr 29 00:50:27 2020 +0200

    columns_indices redudancy fixed and menu_view auto generation

commit 8d96ef46d7f1eb0f26cf8d92203a22890c6165c0
Author: donoban <donoban@riseup.net>
Date:   Sat Apr 25 00:29:53 2020 +0200

    Use col_name instead col number, improves readiblity

commit 1cae3cab93d31592819941eee16ed239805d9cc8
Author: donoban <donoban@riseup.net>
Date:   Fri Apr 24 00:52:12 2020 +0200

    Add QubesNoSuchProperyError

commit aed771d4eb3b6b16652ec1ae27abb0761ebe2fa9
Author: donoban <donoban@riseup.net>
Date:   Fri Apr 24 00:45:59 2020 +0200

    Added missing virt_mode

commit 580749b83376204880da7be93d6325c6cdc0c239
Merge: 70878dc b058db4
Author: donoban <donoban@riseup.net>
Date:   Fri Apr 24 00:16:48 2020 +0200

    Merge branch 'master' of https://github.com/QubesOS/qubes-manager

commit 70878dc647cf34f716cfe0f4753f41cd1487a45e
Author: donoban <donoban@riseup.net>
Date:   Fri Apr 24 00:16:31 2020 +0200

    Let's try travis

commit 5f65477abdb304413c3d3800d6e109c51275e13a
Author: donoban <donoban@riseup.net>
Date:   Fri Apr 24 00:11:37 2020 +0200

    Fix ProgressDialog not being properly drawn

commit b577cb91d908e065ba43e68c613ff0eca449bbd7
Author: donoban <donoban@riseup.net>
Date:   Sun Apr 12 23:44:27 2020 +0200

    pylint fixes and wrong 'outdated'

commit 2a55c5d65b0cb3f7bb9d4adb10f5e41f662a85fe
Author: donoban <donoban@riseup.net>
Date:   Sun Apr 12 23:35:47 2020 +0200

    Restored menubar and toolbar context menu

commit ac7086011328f1ef8f94a838425f8fe872b4fd20
Author: donoban <donoban@riseup.net>
Date:   Sun Apr 12 23:28:02 2020 +0200

    restored logs

commit a0b2b7be3cb6bf2693644289a9ae0452ce330cb5
Author: donoban <donoban@riseup.net>
Date:   Sun Apr 12 23:16:03 2020 +0200

    Removed unused attributes

commit cb514949f55e50925e1eabb19c8303e914c20d17
Author: donoban <donoban@riseup.net>
Date:   Sun Apr 12 23:08:00 2020 +0200

    Part of last commit...

commit 7f0c42fb9a9622d33f5281f8134c7f669a1ae7a4
Author: donoban <donoban@riseup.net>
Date:   Sun Apr 12 23:07:20 2020 +0200

    Save sort settings on closeEvent

commit 8dcfc3c9a9467e512b6c58e8b0a53c727bce7e89
Author: donoban <donoban@riseup.net>
Date:   Sun Apr 12 13:02:37 2020 +0200

    Pylint fixes

commit 8e5f9ff1d4e33d1a8d97842a696ba45ec40c7103
Author: donoban <donoban@riseup.net>
Date:   Mon Apr 6 23:35:15 2020 +0200

    State converted to dict making pylint happier

commit 233ec124736d09f0a64f65ce2d7e19383942e73a
Author: donoban <donoban@riseup.net>
Date:   Mon Apr 6 00:25:34 2020 +0200

    Pylint fixes

commit 37790f01e3755dccbb6da24b3170320fcf2b2fe9
Author: donoban <donoban@riseup.net>
Date:   Sun Apr 5 23:47:17 2020 +0200

    pylint

commit 7dbe393047a00e4d5914368f8dad3c23d5a69586
Author: donoban <donoban@riseup.net>
Date:   Sun Apr 5 23:41:12 2020 +0200

    pylint fixes

commit f79f096ce3307167256308ce44ef8d3cf5f9a824
Author: donoban <donoban@riseup.net>
Date:   Sun Apr 5 23:37:03 2020 +0200

    fixed wrong info_by_id refrences

commit dbf17bde761a6efc03ff29b87e65623a214a44d2
Author: donoban <donoban@riseup.net>
Date:   Sun Apr 5 17:46:31 2020 +0200

    Added QubesCache

    QubesTableModel and main app should operate directly to the cache

commit 42d124520f7910f2ba0e77531fa6f469dd1932e5
Author: donoban <donoban@riseup.net>
Date:   Sun Apr 5 13:50:00 2020 +0200

    Fixing multiple pylint warnings

commit c708b4293035d8d296680b8a7513a066eb475f2b
Author: donoban <donoban@riseup.net>
Date:   Sun Apr 5 12:59:43 2020 +0200

    Added action_open_console setEnabled

commit de1499464d47f145d10250619f83f8dfec2861b5
Author: donoban <donoban@riseup.net>
Date:   Fri Apr 3 00:25:07 2020 +0200

    Forgot context_menu.actions()

commit d24903b2462e416c5148036ed1184b90b02bd8b0
Author: donoban <donoban@riseup.net>
Date:   Fri Apr 3 00:03:16 2020 +0200

    Elegant alternative for _enable_all()

commit a0603870a3bbb78128d4cb23e259d3d00449b94c
Author: donoban <donoban@riseup.net>
Date:   Thu Apr 2 00:22:46 2020 +0200

    Fixed outdate

commit 36e4b310080738bd9d8f9c92a16ad012735eb01a
Author: donoban <donoban@riseup.net>
Date:   Wed Apr 1 11:36:28 2020 +0200

    Removed table_widgets.py dependency

commit 72e679e2d17e663b64213c23530e14cd6f6f843c
Author: donoban <donoban@riseup.net>
Date:   Wed Apr 1 00:55:10 2020 +0200

    Fixed pylint warnings

commit 8e118be165d0ec77d9415cb90ef32c8b73c57612
Author: donoban <donoban@riseup.net>
Date:   Wed Apr 1 00:26:14 2020 +0200

    Added get_selected_vms() and UserRole + 1

commit fd12a95280c5296a92a04bf3dbdb8487c8190729
Author: donoban <donoban@riseup.net>
Date:   Tue Mar 31 01:10:51 2020 +0200

    fix some pylint warnings

commit 09dfe83d89a14ba4a3745ec86ee59ad89ac153ae
Author: donoban <donoban@riseup.net>
Date:   Tue Mar 31 00:34:51 2020 +0200

    Removed unneded margins

commit f0c81bf5a93f51c95b6afb01744f14a387dd4610
Merge: 00876bc f1ad829
Author: donoban <donoban@riseup.net>
Date:   Tue Mar 31 00:33:53 2020 +0200

    Merge branch 'master' of https://github.com/QubesOS/qubes-manager

commit 00876bcbfc7b70cd51848938ceb9f8f969848698
Author: donoban <donoban@riseup.net>
Date:   Mon Mar 30 23:31:18 2020 +0200

    Alternative pyqt imports

    After reading official pyqt doc this seems the standard way
    (Continue previous commit)

commit 6cf09d319021ab7b6491347c579f2911fbcb4e05
Author: donoban <donoban@riseup.net>
Date:   Mon Mar 30 23:29:21 2020 +0200

    Alternative pyqt imports

    After reading official pyqt doc this seems the standard way

commit 410dbaefca27fe3be85fc306db6afc04292f8f6f
Author: donoban <donoban@riseup.net>
Date:   Mon Mar 30 00:12:09 2020 +0200

    Restored sorting and filtering using QSortFilterProxyModel()

commit 0b7fd6e7301009ebab702933b1114254ee5b6a93
Author: donoban <donoban@riseup.net>
Date:   Tue Mar 24 12:46:18 2020 +0100

    Added QSortFilterProyModel

    indexes need proxy.mapToSource(index)

    model.layoutChanged.emit(), replaced by proxy.invalidate()

commit 97440e8a616b84e49e446dc11576a987dae33da2
Author: donoban <donoban@riseup.net>
Date:   Tue Mar 24 12:34:35 2020 +0100

    Removed unneded calls to setContentsMargins

commit 1ad2aaac2cdfa4c7fc4323a3cf82220340de462f
Author: donoban <donoban@riseup.net>
Date:   Sun Mar 22 22:56:33 2020 +0100

    fix removevm with multiselection

commit 19be1da69f3f43b1a9a4d9c5c561d4a6c9004d0c
Author: donoban <donoban@riseup.net>
Date:   Sun Mar 22 22:34:52 2020 +0100

    Restored context menu

commit f43394a446ecb23b36fda029f62f2a0633ee01b6
Author: donoban <donoban@riseup.net>
Date:   Sun Mar 22 00:08:43 2020 +0100

    Deleted unedeed updates after change of settings

commit c98ba627579871b302563f42678ac412e9ccdd48
Merge: 103c572 cf3f102
Author: donoban <donoban@riseup.net>
Date:   Sat Mar 21 23:45:46 2020 +0100

    Merge branch 'master' of https://github.com/QubesOS/qubes-manager

commit 103c5721d3f9f9c1ef6e922aeba053a2eb69b332
Merge: 2756864 da2826d
Author: donoban <donoban@riseup.net>
Date:   Sat Feb 29 16:40:22 2020 +0100

    Merge branch 'master' of https://github.com/QubesOS/qubes-manager

commit 2756864bd04b1b16cf819fb4e726fff40189c8f3
Merge: 2e2a14b 8902727
Author: donoban <donoban@riseup.net>
Date:   Thu Jan 23 23:43:32 2020 +0100

    Merge branch 'master' of https://github.com/QubesOS/qubes-manager

commit 2e2a14bdcaf8f6e7ce2f8fcec944109f18aad27f
Author: donoban <donoban@riseup.net>
Date:   Wed Jan 8 16:41:30 2020 +0100

    Removed fill_table :)

commit 9f3f61a5d0c6c11e9eca81bbedcfe7affa187148
Author: donoban <donoban@riseup.net>
Date:   Tue Dec 31 17:29:39 2019 +0100

    When Template changes status, all AppVMs should update too

commit b970a703ab5bb559b6627c637466558651403f74
Author: donoban <donoban@riseup.net>
Date:   Fri Dec 27 17:59:05 2019 +0100

    Improved multi row system

commit 2f3fc988707252c2079998343de3c508ac4d9a74
Merge: 1f21da6 cca5d7d
Author: donoban <donoban@riseup.net>
Date:   Fri Dec 27 17:25:15 2019 +0100

    Merge remote-tracking branch 'upstream/master'

commit 1f21da6d48d1bdddfc75c3ab47d28e92ed221a6d
Author: donoban <donoban@riseup.net>
Date:   Mon Sep 23 21:41:39 2019 +0200

    Restored 'selection changed' with multiple row support

    It reacts to selection changes but it is missing real functionally yet.

commit bdf16015cd2a4ba894ae1d5c2c495403bb78be0d
Author: donoban <donoban@riseup.net>
Date:   Wed Sep 18 07:27:47 2019 +0200

    Restored add/remove/change events handling

commit 2f9b21f07241b43655fb579dd4130a9c72d3db42
Author: donoban <donoban@riseup.net>
Date:   Wed Sep 18 07:00:49 2019 +0200

    Added StateIconDelegate and StateInfo

    Used for paint different icons on same cell with custom tooltips.

commit ccfa5453b2fe1ca5948406126a0f32a2caf4bde0
Author: donoban <donoban@riseup.net>
Date:   Wed Sep 18 06:35:12 2019 +0200

    Removed Default and Minium horizonal header section size

    It affects resizeColumnsToContents()

commit 628073e9522af5bff83224491645addbdcfb7418
Author: donoban <donoban@riseup.net>
Date:   Sun Sep 15 10:45:36 2019 +0200

    Uncompatible with TableView

commit 52ddd56bf293ca704205824f9c3b0f25f2c8d4c4
Merge: 0a87cf9 1ced452
Author: donoban <donoban@riseup.net>
Date:   Sun Sep 15 10:43:13 2019 +0200

    Merge branch 'master' of https://github.com/QubesOS/qubes-manager

commit 0a87cf963388bc9a33d241146e642a8ce9518ddb
Author: donoban <donoban@riseup.net>
Date:   Mon Sep 2 21:55:21 2019 +0200

    Restored precises updates
    https://github.com/QubesOS/qubes-manager/pull/195#issuecomment-525795486

commit 030bf13fab31cd57c5891d6ff692faf57c500f0a
Author: donoban <donoban@riseup.net>
Date:   Sun Aug 25 18:33:11 2019 +0200

    New and dirty first Model/View version

commit 981ee9c1c3ccd6af4fe8b2745b7b5ddb29ecc0c4
Author: donoban <donoban@riseup.net>
Date:   Sun Aug 25 18:32:28 2019 +0200

    QtableWidget > QTableView

commit 41beaed24b69e7e9dc9223fa100605b0fd5bb40e
Author: donoban <donoban@riseup.net>
Date:   Sun Aug 25 18:31:59 2019 +0200

    Removed table_widgets
This commit is contained in:
donoban 2020-07-30 02:40:40 +02:00 committed by Marek Marczykowski-Górecki
parent e4be77b75b
commit bb1995af2e
No known key found for this signature in database
GPG Key ID: 063938BA42CFA724
8 changed files with 980 additions and 1445 deletions

View File

@ -14,6 +14,7 @@ ignore=tests,
ui_restoredlg.py, ui_restoredlg.py,
ui_settingsdlg.py, ui_settingsdlg.py,
resources_rc.py resources_rc.py
extension-pkg-whitelist=PyQt5
[MESSAGES CONTROL] [MESSAGES CONTROL]
# abstract-class-little-used: see http://www.logilab.org/ticket/111138 # abstract-class-little-used: see http://www.logilab.org/ticket/111138

View File

@ -33,7 +33,6 @@ SOURCES = \
qubesmanager/resources_rc.py \ qubesmanager/resources_rc.py \
qubesmanager/restore.py \ qubesmanager/restore.py \
qubesmanager/settings.py \ qubesmanager/settings.py \
qubesmanager/table_widgets.py \
qubesmanager/template_manager.py \ qubesmanager/template_manager.py \
qubesmanager/ui_about.py \ qubesmanager/ui_about.py \
qubesmanager/ui_backupdlg.py \ qubesmanager/ui_backupdlg.py \

File diff suppressed because it is too large Load Diff

View File

@ -1,510 +0,0 @@
#!/usr/bin/python3
# -*- coding: utf8 -*-
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2014 Marek Marczykowski-Górecki
# <marmarek@invisiblethingslab.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with this program; if not, see <http://www.gnu.org/licenses/>.
import datetime
from PyQt5 import QtWidgets, QtCore, QtGui # pylint: disable=import-error
# pylint: disable=too-few-public-methods
power_order = QtCore.Qt.DescendingOrder
update_order = QtCore.Qt.AscendingOrder
row_height = 30
class VmIconWidget(QtWidgets.QWidget):
def __init__(self, icon_path, enabled=True, size_multiplier=0.7,
tooltip=None, parent=None,
icon_sz=(32, 32)): # pylint: disable=unused-argument
super(VmIconWidget, self).__init__(parent)
self.enabled = enabled
self.size_multiplier = size_multiplier
self.label_icon = QtWidgets.QLabel()
self.set_icon(icon_path)
if tooltip is not None:
self.label_icon.setToolTip(tooltip)
layout = QtWidgets.QHBoxLayout()
layout.addWidget(self.label_icon)
layout.setContentsMargins(0, 0, 0, 0)
self.setLayout(layout)
def setToolTip(self, tooltip): # pylint: disable=invalid-name
if tooltip is not None:
self.label_icon.setToolTip(tooltip)
else:
self.label_icon.setToolTip('')
def set_icon(self, icon_path):
if icon_path[0] in ':/':
icon = QtGui.QIcon(icon_path)
else:
icon = QtGui.QIcon.fromTheme(icon_path)
icon_sz = QtCore.QSize(row_height * self.size_multiplier,
row_height * self.size_multiplier)
icon_pixmap = icon.pixmap(
icon_sz,
QtGui.QIcon.Disabled if not self.enabled else QtGui.QIcon.Normal)
self.label_icon.setPixmap(icon_pixmap)
self.label_icon.setFixedSize(icon_sz)
class VmTypeWidget(VmIconWidget):
class VmTypeItem(QtWidgets.QTableWidgetItem):
def __init__(self, value, vm):
super(VmTypeWidget.VmTypeItem, self).__init__()
self.value = value
self.qid = vm.qid
self.name = vm.name
def set_value(self, value):
self.value = value
# pylint: disable=too-many-return-statements
def __lt__(self, other):
if self.qid == 0:
return True
if other.qid == 0:
return False
if self.value == other.value:
return self.name < other.name
return self.value < other.value
def __init__(self, vm, parent=None):
(icon_path, tooltip) = self.get_vm_icon(vm)
super(VmTypeWidget, self).__init__(
icon_path, True, 0.8, tooltip, parent)
self.vm = vm
self.table_item = self.VmTypeItem(self.value, vm)
self.value = None
# TODO: add "provides network" column
def get_vm_icon(self, vm):
if vm.klass == 'AdminVM':
self.value = 0
icon_name = "dom0"
elif vm.klass == 'TemplateVM':
self.value = 3
icon_name = "templatevm"
elif vm.klass == 'StandaloneVM':
self.value = 4
icon_name = "standalonevm"
else:
self.value = 5 + vm.label.index
icon_name = "appvm"
return ":/" + icon_name + ".png", vm.klass
class VmLabelWidget(VmIconWidget):
class VmLabelItem(QtWidgets.QTableWidgetItem):
def __init__(self, value, vm):
super(VmLabelWidget.VmLabelItem, self).__init__()
self.value = value
self.qid = vm.qid
self.name = vm.name
def set_value(self, value):
self.value = value
# pylint: disable=too-many-return-statements
def __lt__(self, other):
if self.qid == 0:
return True
if other.qid == 0:
return False
if self.value == other.value:
return self.name < other.name
return self.value < other.value
def __init__(self, vm, parent=None):
self.icon_path = self.get_vm_icon_path(vm)
super(VmLabelWidget, self).__init__(self.icon_path,
True, 0.8, None, parent)
self.vm = vm
self.table_item = self.VmLabelItem(self.value, vm)
self.value = None
def get_vm_icon_path(self, vm):
self.value = vm.label.index
return vm.label.icon
def update(self):
icon_path = self.get_vm_icon_path(self.vm)
if icon_path != self.icon_path:
self.icon_path = icon_path
self.set_icon(icon_path)
class VmStatusIcon(QtWidgets.QLabel):
def __init__(self, vm, parent=None):
super(VmStatusIcon, self).__init__(parent)
self.vm = vm
self.status = None
self.set_on_icon()
self.previous_power_state = self.vm.get_power_state()
def update(self):
if self.previous_power_state != self.vm.get_power_state():
self.set_on_icon()
self.previous_power_state = self.vm.get_power_state()
def set_on_icon(self):
if self.vm.get_power_state() == "Running":
icon = QtGui.QIcon(":/on.png")
self.status = 3
elif self.vm.get_power_state() in ["Paused", "Suspended"]:
icon = QtGui.QIcon(":/paused.png")
self.status = 2
elif self.vm.get_power_state() in ["Transient", "Halting", "Dying"]:
icon = QtGui.QIcon(":/transient.png")
self.status = 1
else:
icon = QtGui.QIcon(":/off.png")
self.status = 0
icon_sz = QtCore.QSize(row_height * 0.5, row_height * 0.5)
icon_pixmap = icon.pixmap(icon_sz)
self.setPixmap(icon_pixmap)
self.setFixedSize(icon_sz)
class VmInfoWidget(QtWidgets.QWidget):
class VmInfoItem(QtWidgets.QTableWidgetItem):
def __init__(self, on_icon, upd_info_item, vm):
super(VmInfoWidget.VmInfoItem, self).__init__()
self.on_icon = on_icon
self.upd_info_item = upd_info_item
self.vm = vm
self.qid = vm.qid
self.name = vm.name
def __lt__(self, other):
# pylint: disable=too-many-return-statements
if self.qid == 0:
return True
if other.qid == 0:
return False
self_val = self.upd_info_item.value
other_val = other.upd_info_item.value
if self.tableWidget().\
horizontalHeader().sortIndicatorOrder() == update_order:
# the result will be sorted by upd, sorting order: Ascending
self_val += 1 if self.on_icon.status > 0 else 0
other_val += 1 if other.on_icon.status > 0 else 0
if self_val == other_val:
return self.name < other.name
return self_val > other_val
if self.tableWidget().\
horizontalHeader().sortIndicatorOrder() == power_order:
# the result will be sorted by power state,
# sorting order: Descending
if self.on_icon.status == other.on_icon.status:
return self.name < other.name
return self_val > other_val
# it would be strange if this happened
return
def __init__(self, vm, parent=None):
super(VmInfoWidget, self).__init__(parent)
self.vm = vm
layout = QtWidgets.QHBoxLayout()
self.on_icon = VmStatusIcon(vm)
self.upd_info = VmUpdateInfoWidget(vm, show_text=False)
self.error_icon = VmIconWidget(":/warning.png")
self.blk_icon = VmIconWidget(":/mount.png")
self.rec_icon = VmIconWidget(":/mic.png")
layout.addWidget(self.on_icon)
layout.addWidget(self.upd_info)
layout.addWidget(self.error_icon)
layout.addItem(QtWidgets.QSpacerItem(0, 10,
QtWidgets.QSizePolicy.Expanding,
QtWidgets.QSizePolicy.Expanding))
layout.addWidget(self.blk_icon)
layout.addWidget(self.rec_icon)
layout.setContentsMargins(5, 0, 5, 0)
self.setLayout(layout)
self.rec_icon.setVisible(False)
self.blk_icon.setVisible(False)
self.error_icon.setVisible(False)
self.table_item = self.VmInfoItem(self.on_icon,
self.upd_info.table_item, vm)
def update_vm_state(self):
self.on_icon.update()
self.upd_info.update_outdated()
class VMPropertyItem(QtWidgets.QTableWidgetItem):
def __init__(self, vm, property_name, empty_function=(lambda x: False),
check_default=False):
"""
Class used to represent Qube Manager table widget.
:param vm: vm object
:param property_name: name of the property the widget represents
:param empty_function: a function that, when applied to values of
vm.property_name, returns True when the property value should be
represented as an empty string and False otherwise; by default this
function always returns false (vm.property_name is represented by an
empty string only when it actually is one)
:param check_default: if True, the widget will prepend its text with
"default" if the if the property is set to DEFAULT
"""
super(VMPropertyItem, self).__init__()
self.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
self.setTextAlignment(QtCore.Qt.AlignVCenter)
self.vm = vm
self.qid = vm.qid
self.property_name = property_name
self.name = vm.name
self.empty_function = empty_function
self.check_default = check_default
self.update()
def update(self):
val = getattr(self.vm, self.property_name, None)
if self.empty_function(val):
text = ""
elif val is None:
text = QtCore.QCoreApplication.translate("QubeManager", "n/a")
elif val is True:
text = QtCore.QCoreApplication.translate("QubeManager", "Yes")
else:
text = str(val)
if self.check_default and hasattr(self.vm, self.property_name) and \
self.vm.property_is_default(self.property_name):
text = QtCore.QCoreApplication.translate(
"QubeManager", 'default ({})').format(text)
self.setText(text)
def __lt__(self, other):
if self.qid == 0:
return True
if other.qid == 0:
return False
if self.text() == other.text():
return self.name < other.name
return super(VMPropertyItem, self).__lt__(other)
class VmTemplateItem(VMPropertyItem):
def __init__(self, vm):
super(VmTemplateItem, self).__init__(vm, "template")
def update(self):
if getattr(self.vm, 'template', None) is not None:
self.setText(self.vm.template.name)
else:
font = QtGui.QFont()
font.setStyle(QtGui.QFont.StyleItalic)
self.setFont(font)
self.setForeground(QtGui.QBrush(QtGui.QColor("gray")))
self.setText(self.vm.klass)
class VmInternalItem(VMPropertyItem):
def __init__(self, vm):
super(VmInternalItem, self).__init__(vm, None)
def update(self):
internal = self.vm.features.get('internal', False)
self.setText(QtCore.QCoreApplication.translate(
"QubeManager", "Yes") if internal else "")
# features man qvm-features
class VmUpdateInfoWidget(QtWidgets.QWidget):
class VmUpdateInfoItem(QtWidgets.QTableWidgetItem):
def __init__(self, value, vm):
super(VmUpdateInfoWidget.VmUpdateInfoItem, self).__init__()
self.value = 0
self.vm = vm
self.qid = vm.qid
self.name = vm.name
self.set_value(value)
def set_value(self, value):
if value in ("outdated", "to-be-outdated"):
self.value = 30
elif value == "update":
self.value = 20
else:
self.value = 0
def __lt__(self, other):
if self.qid == 0:
return True
if other.qid == 0:
return False
if self.value == other.value:
return self.name < other.name
return self.value < other.value
def __init__(self, vm, show_text=True, parent=None):
super(VmUpdateInfoWidget, self).__init__(parent)
layout = QtWidgets.QHBoxLayout()
self.show_text = show_text
if self.show_text:
self.label = QtWidgets.QLabel("")
layout.addWidget(self.label, alignment=QtCore.Qt.AlignCenter)
else:
self.icon = QtWidgets.QLabel("")
layout.addWidget(self.icon, alignment=QtCore.Qt.AlignCenter)
self.setLayout(layout)
self.vm = vm
self.previous_outdated_state = None
self.previous_update_recommended = None
self.value = None
self.table_item = VmUpdateInfoWidget.VmUpdateInfoItem(self.value, vm)
self.update_outdated()
def update_outdated(self):
outdated_state = False
is_disposable = getattr(self.vm, 'auto_cleanup', False)
if not is_disposable and self.vm.is_running():
if hasattr(self.vm, 'template') and self.vm.template.is_running():
outdated_state = "to-be-outdated"
if not outdated_state:
for vol in self.vm.volumes.values():
if vol.is_outdated():
outdated_state = "outdated"
break
if not is_disposable and \
self.vm.klass in {'TemplateVM', 'StandaloneVM'} and \
self.vm.features.get('updates-available', False):
outdated_state = 'update'
self.update_status_widget(outdated_state)
def update_status_widget(self, state):
if state == self.previous_outdated_state:
return
self.previous_outdated_state = state
self.value = state
self.table_item.set_value(state)
if state == "update":
label_text = "<font color=\"#CCCC00\">{}</font>".format(
QtCore.QCoreApplication.translate("QubeManager",
"Check updates"))
icon_path = ":/update-recommended.png"
tooltip_text = QtCore.QCoreApplication.translate("QubeManager",
"Updates pending!")
elif state == "outdated":
label_text = "<font color=\"red\">{}</font>".format(
QtCore.QCoreApplication.translate("QubeManager",
"Qube outdated"))
icon_path = ":/outdated.png"
tooltip_text = QtCore.QCoreApplication.translate(
"QubeManager",
"The qube must be restarted for its filesystem to reflect the "
"template's recent committed changes.")
elif state == "to-be-outdated":
label_text = "<font color=\"#800000\">{}</font>".format(
QtCore.QCoreApplication.translate("QubeManager",
"Template running"))
icon_path = ":/to-be-outdated.png"
tooltip_text = QtCore.QCoreApplication.translate(
"QubeManager",
"The Template must be stopped before changes from its "
"current session can be picked up by this qube.")
else:
label_text = None
tooltip_text = None
icon_path = None
if hasattr(self, 'icon'):
self.icon.setVisible(False)
self.layout().removeWidget(self.icon)
del self.icon
if self.show_text:
self.label.setText(label_text)
else:
if icon_path is not None:
self.icon = VmIconWidget(icon_path, True, 0.7)
self.icon.setToolTip(tooltip_text)
self.layout().addWidget(self.icon,
alignment=QtCore.Qt.AlignCenter)
self.icon.setVisible(True)
class VmSizeOnDiskItem(QtWidgets.QTableWidgetItem):
def __init__(self, vm):
super(VmSizeOnDiskItem, self).__init__()
self.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
self.vm = vm
self.qid = vm.qid
self.name = vm.name
self.value = 0
self.update()
self.setTextAlignment(QtCore.Qt.AlignVCenter)
def update(self):
if self.vm.qid == 0:
self.setText(QtCore.QCoreApplication.translate("QubeManager",
"n/a"))
else:
self.value = 10
self.value = round(self.vm.get_disk_utilization()/(1024*1024), 2)
self.setText(str(self.value) + " MiB")
def __lt__(self, other):
if self.qid == 0:
return True
if other.qid == 0:
return False
if self.value == other.value:
return self.name < other.name
return self.value < other.value
class VmLastBackupItem(VMPropertyItem):
def __init__(self, vm, property_name):
super(VmLastBackupItem, self).__init__(vm, property_name)
def update(self):
backup_timestamp = getattr(self.vm, 'backup_timestamp', None)
if backup_timestamp:
self.setText(
str(datetime.datetime.fromtimestamp(backup_timestamp)))
else:
self.setText("")

View File

@ -30,11 +30,16 @@ import datetime
import time import time
from PyQt5 import QtTest, QtCore, QtWidgets from PyQt5 import QtTest, QtCore, QtWidgets
from PyQt5.QtCore import (Qt, QSize)
from PyQt5.QtGui import (QIcon)
from qubesadmin import Qubes, events, exc from qubesadmin import Qubes, events, exc
import qubesmanager.qube_manager as qube_manager import qubesmanager.qube_manager as qube_manager
from qubesmanager.tests import init_qtapp from qubesmanager.tests import init_qtapp
icon_size = QSize(24, 24)
class QubeManagerTest(unittest.TestCase): class QubeManagerTest(unittest.TestCase):
def setUp(self): def setUp(self):
super(QubeManagerTest, self).setUp() super(QubeManagerTest, self).setUp()
@ -58,14 +63,14 @@ class QubeManagerTest(unittest.TestCase):
def test_001_correct_vms_listed(self): def test_001_correct_vms_listed(self):
vms_in_table = [] vms_in_table = []
for row in range(self.dialog.table.rowCount()): for row in range(self.dialog.table.model().rowCount()):
vm = self._get_table_item(row, "Name").vm vm = self._get_table_vm(row)
self.assertIsNotNone(vm) self.assertIsNotNone(vm)
vms_in_table.append(vm.name) vms_in_table.append(vm.name)
# check that name is listed correctly # check that name is listed correctly
name_item = self._get_table_item(row, "Name") name_item = self._get_table_item(row, "Name")
self.assertEqual(name_item.text(), vm.name, self.assertEqual(name_item, vm.name,
"Incorrect VM name for {}".format(vm.name)) "Incorrect VM name for {}".format(vm.name))
actual_vms = [vm.name for vm in self.qapp.domains] actual_vms = [vm.name for vm in self.qapp.domains]
@ -76,39 +81,42 @@ class QubeManagerTest(unittest.TestCase):
"Incorrect VMs loaded") "Incorrect VMs loaded")
def test_002_correct_template_listed(self): def test_002_correct_template_listed(self):
for row in range(self.dialog.table.rowCount()): for row in range(self.dialog.table.model().rowCount()):
vm = self._get_table_item(row, "Name").vm vm = self._get_table_vm(row)
# check that template is listed correctly # check that template is listed correctly
template_item = self._get_table_item(row, "Template") template_item = self._get_table_item(row, "Template")
if getattr(vm, "template", None): if getattr(vm, "template", None):
self.assertEqual(vm.template, self.assertEqual(vm.template,
template_item.text(), template_item,
"Incorrect template for {}".format(vm.name)) "Incorrect template for {}".format(vm.name))
else: else:
self.assertEqual(vm.klass, template_item.text(), self.assertEqual(vm.klass, template_item,
"Incorrect class for {}".format(vm.name)) "Incorrect class for {}".format(vm.name))
def test_003_correct_netvm_listed(self): def test_003_correct_netvm_listed(self):
for row in range(self.dialog.table.rowCount()): for row in range(self.dialog.table.model().rowCount()):
vm = self._get_table_item(row, "Name").vm vm = self._get_table_vm(row)
# check that netvm is listed correctly # check that netvm is listed correctly
netvm_item = self._get_table_item(row, "NetVM") netvm_item = self._get_table_item(row, "NetVM")
netvm_value = getattr(vm, "netvm", None) netvm_value = getattr(vm, "netvm", None)
netvm_value = "n/a" if not netvm_value else netvm_value
if not netvm_value:
netvm_value = "n/a"
if netvm_value and hasattr(vm, "netvm") \ if netvm_value and hasattr(vm, "netvm") \
and vm.property_is_default("netvm"): and vm.property_is_default("netvm"):
netvm_value = "default ({})".format(netvm_value) netvm_value = "default ({})".format(netvm_value)
self.assertEqual(netvm_value, self.assertEqual(netvm_value,
netvm_item.text(), netvm_item,
"Incorrect netvm for {}".format(vm.name)) "Incorrect netvm for {}".format(vm.name))
def test_004_correct_disk_usage_listed(self): def test_004_correct_disk_usage_listed(self):
for row in range(self.dialog.table.rowCount()): for row in range(self.dialog.table.model().rowCount()):
vm = self._get_table_item(row, "Name").vm vm = self._get_table_vm(row)
size_item = self._get_table_item(row, "Size") size_item = self._get_table_item(row, "Disk Usage")
if vm.klass == 'AdminVM': if vm.klass == 'AdminVM':
size_value = "n/a" size_value = "n/a"
else: else:
@ -116,22 +124,22 @@ class QubeManagerTest(unittest.TestCase):
size_value = str(size_value) + " MiB" size_value = str(size_value) + " MiB"
self.assertEqual(size_value, self.assertEqual(size_value,
size_item.text(), size_item,
"Incorrect size for {}".format(vm.name)) "Incorrect size for {}".format(vm.name))
def test_005_correct_internal_listed(self): def test_005_correct_internal_listed(self):
for row in range(self.dialog.table.rowCount()): for row in range(self.dialog.table.model().rowCount()):
vm = self._get_table_item(row, "Name").vm vm = self._get_table_vm(row)
internal_item = self._get_table_item(row, "Internal") internal_item = self._get_table_item(row, "Internal")
internal_value = "Yes" if vm.features.get('internal', False) else "" internal_value = "Yes" if vm.features.get('internal', False) else ""
self.assertEqual(internal_item.text(), internal_value, self.assertEqual(internal_item, internal_value,
"Incorrect internal value for {}".format(vm.name)) "Incorrect internal value for {}".format(vm.name))
def test_006_correct_ip_listed(self): def test_006_correct_ip_listed(self):
for row in range(self.dialog.table.rowCount()): for row in range(self.dialog.table.model().rowCount()):
vm = self._get_table_item(row, "Name").vm vm = self._get_table_vm(row)
ip_item = self._get_table_item(row, "IP") ip_item = self._get_table_item(row, "IP")
if hasattr(vm, 'ip'): if hasattr(vm, 'ip'):
@ -140,24 +148,24 @@ class QubeManagerTest(unittest.TestCase):
else: else:
ip_value = "n/a" ip_value = "n/a"
self.assertEqual(ip_value, ip_item.text(), self.assertEqual(ip_value, ip_item,
"Incorrect ip value for {}".format(vm.name)) "Incorrect ip value for {}".format(vm.name))
def test_007_incl_in_backups_listed(self): def test_007_incl_in_backups_listed(self):
for row in range(self.dialog.table.rowCount()): for row in range(self.dialog.table.model().rowCount()):
vm = self._get_table_item(row, "Name").vm vm = self._get_table_vm(row)
incl_backups_item = self._get_table_item(row, "Include in backups") incl_backups_item = self._get_table_item(row, "Include in backups")
incl_backups_value = getattr(vm, 'include_in_backups', False) incl_backups_value = getattr(vm, 'include_in_backups', False)
incl_backups_value = "Yes" if incl_backups_value else "" incl_backups_value = "Yes" if incl_backups_value else ""
self.assertEqual( self.assertEqual(
incl_backups_value, incl_backups_item.text(), incl_backups_value, incl_backups_item,
"Incorrect include in backups value for {}".format(vm.name)) "Incorrect include in backups value for {}".format(vm.name))
def test_008_last_backup_listed(self): def test_008_last_backup_listed(self):
for row in range(self.dialog.table.rowCount()): for row in range(self.dialog.table.model().rowCount()):
vm = self._get_table_item(row, "Name").vm vm = self._get_table_vm(row)
last_backup_item = self._get_table_item(row, "Last backup") last_backup_item = self._get_table_item(row, "Last backup")
last_backup_value = getattr(vm, 'backup_timestamp', None) last_backup_value = getattr(vm, 'backup_timestamp', None)
@ -165,16 +173,14 @@ class QubeManagerTest(unittest.TestCase):
if last_backup_value: if last_backup_value:
last_backup_value = str( last_backup_value = str(
datetime.datetime.fromtimestamp(last_backup_value)) datetime.datetime.fromtimestamp(last_backup_value))
else:
last_backup_value = ""
self.assertEqual( self.assertEqual(
last_backup_value, last_backup_item.text(), last_backup_value, last_backup_item,
"Incorrect last backup value for {}".format(vm.name)) "Incorrect last backup value for {}".format(vm.name))
def test_009_def_dispvm_listed(self): def test_009_def_dispvm_listed(self):
for row in range(self.dialog.table.rowCount()): for row in range(self.dialog.table.model().rowCount()):
vm = self._get_table_item(row, "Name").vm vm = self._get_table_vm(row)
def_dispvm_item = self._get_table_item(row, "Default DispVM") def_dispvm_item = self._get_table_item(row, "Default DispVM")
if vm.property_is_default("default_dispvm"): if vm.property_is_default("default_dispvm"):
@ -184,45 +190,40 @@ class QubeManagerTest(unittest.TestCase):
def_dispvm_value = getattr(vm, "default_dispvm", None) def_dispvm_value = getattr(vm, "default_dispvm", None)
self.assertEqual( self.assertEqual(
str(def_dispvm_value), def_dispvm_item.text(), def_dispvm_value, def_dispvm_item,
"Incorrect default dispvm value for {}".format(vm.name)) "Incorrect default dispvm value for {}".format(vm.name))
def test_010_is_dvm_template_listed(self): def test_010_is_dvm_template_listed(self):
for row in range(self.dialog.table.rowCount()): for row in range(self.dialog.table.model().rowCount()):
vm = self._get_table_item(row, "Name").vm vm = self._get_table_vm(row)
is_dvm_template_item = self._get_table_item(row, "Is DVM Template") is_dvm_template_item = self._get_table_item(row, "Is DVM Template")
is_dvm_template_value = "Yes" if \ is_dvm_template_value = "Yes" if \
getattr(vm, "template_for_dispvms", False) else "" getattr(vm, "template_for_dispvms", False) else ""
self.assertEqual( self.assertEqual(
is_dvm_template_value, is_dvm_template_item.text(), is_dvm_template_value, is_dvm_template_item,
"Incorrect is DVM template value for {}".format(vm.name)) "Incorrect is DVM template value for {}".format(vm.name))
def test_011_is_label_correct(self): def test_011_is_label_correct(self):
for row in range(self.dialog.table.rowCount()): for row in range(self.dialog.table.model().rowCount()):
vm = self._get_table_item(row, "Name").vm vm = self._get_table_vm(row)
icon = QIcon.fromTheme(vm.label.icon)
icon = icon.pixmap(icon_size)
label_item = self._get_table_item(row, "Label")
self.assertEqual(label_item.icon_path, vm.label.icon) label_pixmap = self._get_table_item(row, "Label", Qt.DecorationRole)
self.assertEqual(label_pixmap.toImage(), icon.toImage())
def test_012_is_state_correct(self): def test_012_is_state_correct(self):
for row in range(self.dialog.table.rowCount()): for row in range(self.dialog.table.model().rowCount()):
vm = self._get_table_item(row, "Name").vm vm = self._get_table_vm(row)
state_item = self._get_table_item(row, "State") displayed_power_state = self._get_table_item(row, "State")['power']
# this should not be done like that in table_widgets
displayed_power_state = state_item.on_icon.status
if vm.is_running():
correct_power_state = 3
else:
correct_power_state = 0
self.assertEqual( self.assertEqual(
displayed_power_state, correct_power_state, displayed_power_state, vm.get_power_state(),
"Wrong power state displayed for {}".format(vm.name)) "Wrong power state displayed for {}".format(vm.name))
def test_013_incorrect_settings_file(self): def test_013_incorrect_settings_file(self):
@ -245,25 +246,23 @@ class QubeManagerTest(unittest.TestCase):
self.assertEqual(mock_warning.call_count, 1) self.assertEqual(mock_warning.call_count, 1)
def test_100_sorting(self): def test_100_sorting(self):
col = self.dialog.qubes_model.columns_indices.index("Template")
self.dialog.table.sortByColumn(self.dialog.columns_indices["Template"], self.dialog.table.sortByColumn(col, QtCore.Qt.AscendingOrder)
QtCore.Qt.AscendingOrder)
self.__check_sorting("Template") self.__check_sorting("Template")
self.dialog.table.sortByColumn(self.dialog.columns_indices["Name"], col = self.dialog.qubes_model.columns_indices.index("Name")
QtCore.Qt.AscendingOrder) self.dialog.table.sortByColumn(col, QtCore.Qt.AscendingOrder)
self.__check_sorting("Name") self.__check_sorting("Name")
@unittest.mock.patch('qubesmanager.qube_manager.QtCore.QSettings.setValue') @unittest.mock.patch('qubesmanager.qube_manager.QSettings.setValue')
@unittest.mock.patch('qubesmanager.qube_manager.QtCore.QSettings.sync') def test_101_hide_column(self, mock_settings):
def test_101_hide_column(self, mock_sync, mock_settings): model = self.dialog.qubes_model
self.dialog.action_is_dvm_template.trigger() action_no = model.columns_indices.index('Is DVM Template')
mock_settings.assert_called_with('columns/Is DVM Template', False) self.dialog.menu_view.actions()[action_no].trigger()
self.assertEqual(mock_sync.call_count, 1, "Hidden column not synced")
self.dialog.action_is_dvm_template.trigger()
mock_settings.assert_called_with('columns/Is DVM Template', True) mock_settings.assert_called_with('columns/Is DVM Template', True)
self.assertEqual(mock_sync.call_count, 2, "Hidden column not synced")
self.dialog.menu_view.actions()[action_no].trigger()
mock_settings.assert_called_with('columns/Is DVM Template', False)
@unittest.mock.patch('qubesmanager.settings.VMSettingsWindow') @unittest.mock.patch('qubesmanager.settings.VMSettingsWindow')
def test_200_vm_open_settings(self, mock_window): def test_200_vm_open_settings(self, mock_window):
@ -282,9 +281,9 @@ class QubeManagerTest(unittest.TestCase):
self.assertFalse(self.dialog.action_settings.isEnabled(), self.assertFalse(self.dialog.action_settings.isEnabled(),
"Settings not disabled for admin VM") "Settings not disabled for admin VM")
self.assertFalse(self.dialog.action_editfwrules.isEnabled(), self.assertFalse(self.dialog.action_editfwrules.isEnabled(),
"Settings not disabled for admin VM") "Editfw not disabled for admin VM")
self.assertFalse(self.dialog.action_appmenus.isEnabled(), self.assertFalse(self.dialog.action_appmenus.isEnabled(),
"Settings not disabled for admin VM") "Appmenus not disabled for admin VM")
@unittest.mock.patch('qubesmanager.settings.VMSettingsWindow') @unittest.mock.patch('qubesmanager.settings.VMSettingsWindow')
def test_202_vm_open_firewall(self, mock_window): def test_202_vm_open_firewall(self, mock_window):
@ -461,16 +460,17 @@ class QubeManagerTest(unittest.TestCase):
self.assertFalse(self.dialog.action_removevm.isEnabled()) self.assertFalse(self.dialog.action_removevm.isEnabled())
@unittest.mock.patch("PyQt5.QtWidgets.QMessageBox") @unittest.mock.patch("qubesmanager.qube_manager.QMessageBox")
@unittest.mock.patch('qubesadmin.utils.vm_dependencies') @unittest.mock.patch('qubesadmin.utils.vm_dependencies')
def test_218_remove_vm_dependencies(self, mock_dependencies, mock_msgbox): def test_218_remove_vm_dependencies(self, mock_dependencies, mock_msgbox):
action = self.dialog.action_removevm
mock_vm = unittest.mock.Mock(spec=['name'], mock_vm = unittest.mock.Mock(spec=['name'],
**{'name.return_value': 'test-vm'}) **{'name.return_value': 'test-vm'})
mock_dependencies.return_value = [(mock_vm, "test_prop")] mock_dependencies.return_value = [(mock_vm, "test_prop")]
action = self.dialog.action_removevm
self._select_non_admin_vm()
action.trigger() action.trigger()
mock_msgbox().show.assert_called_with() mock_msgbox().show.assert_called_with()
@unittest.mock.patch('PyQt5.QtWidgets.QMessageBox.warning') @unittest.mock.patch('PyQt5.QtWidgets.QMessageBox.warning')
@ -486,7 +486,7 @@ class QubeManagerTest(unittest.TestCase):
with unittest.mock.patch('qubesmanager.common_threads.RemoveVMThread')\ with unittest.mock.patch('qubesmanager.common_threads.RemoveVMThread')\
as mock_thread: as mock_thread:
mock_input.return_value = (selected_vm.name, False) mock_input.return_value = (selected_vm, False)
action.trigger() action.trigger()
self.assertEqual(mock_thread.call_count, 0, self.assertEqual(mock_thread.call_count, 0,
"VM removed despite user clicking 'cancel") "VM removed despite user clicking 'cancel")
@ -766,7 +766,7 @@ class QubeManagerTest(unittest.TestCase):
self.assertEqual(len(self.dialog.threads_list), 3) self.assertEqual(len(self.dialog.threads_list), 3)
def test_400_event_domain_added(self): def test_400_event_domain_added(self):
number_of_vms = self.dialog.table.rowCount() number_of_vms = self.dialog.table.model().rowCount()
self.addCleanup(subprocess.call, ["qvm-remove", "-f", "test-vm"]) self.addCleanup(subprocess.call, ["qvm-remove", "-f", "test-vm"])
@ -774,7 +774,7 @@ class QubeManagerTest(unittest.TestCase):
["qvm-create", "--label", "red", "test-vm"]) ["qvm-create", "--label", "red", "test-vm"])
# a single row was added to the table # a single row was added to the table
self.assertEqual(self.dialog.table.rowCount(), number_of_vms + 1) self.assertEqual(self.dialog.table.model().rowCount(), number_of_vms+1)
# table contains the correct vms # table contains the correct vms
vms_in_table = self._create_set_of_current_vms() vms_in_table = self._create_set_of_current_vms()
@ -785,15 +785,14 @@ class QubeManagerTest(unittest.TestCase):
"correctly after add") "correctly after add")
# check if sorting works # check if sorting works
self.dialog.table.sortItems(self.dialog.columns_indices["Name"],
QtCore.Qt.AscendingOrder)
self.__check_sorting("Name") self.__check_sorting("Name")
# try opening settings for the added vm # try opening settings for the added vm
for row in range(self.dialog.table.rowCount()): for row in range(self.dialog.table.model().rowCount()):
name = self._get_table_item(row, "Name") name = self._get_table_item(row, "Name")
if name.text() == "test-vm": if name == "test-vm":
self.dialog.table.setCurrentItem(name) index = self.dialog.table.model().index(row, 0)
self.dialog.table.setCurrentIndex(index)
break break
with unittest.mock.patch('qubesmanager.settings.VMSettingsWindow')\ with unittest.mock.patch('qubesmanager.settings.VMSettingsWindow')\
as mock_settings: as mock_settings:
@ -816,8 +815,6 @@ class QubeManagerTest(unittest.TestCase):
self.assertEqual(initial_vms, current_vms) self.assertEqual(initial_vms, current_vms)
# check if sorting works # check if sorting works
self.dialog.table.sortItems(self.dialog.columns_indices["Name"],
QtCore.Qt.AscendingOrder)
self.__check_sorting("Name") self.__check_sorting("Name")
def test_403_event_dispvm_added(self): def test_403_event_dispvm_added(self):
@ -874,27 +871,28 @@ class QubeManagerTest(unittest.TestCase):
target_vm_name = "work" target_vm_name = "work"
vm_row = self._find_vm_row(target_vm_name) vm_row = self._find_vm_row(target_vm_name)
current_label_path = self._get_table_item(vm_row, "Label").icon_path current_label = self._get_table_item(vm_row, "Label", Qt.DecorationRole)
self.addCleanup( self.addCleanup(
subprocess.call, ["qvm-prefs", target_vm_name, "label", "blue"]) subprocess.call, ["qvm-prefs", target_vm_name, "label", "blue"])
self._run_command_and_process_events( self._run_command_and_process_events(
["qvm-prefs", target_vm_name, "label", "red"]) ["qvm-prefs", target_vm_name, "label", "red"])
new_label_path = self._get_table_item(vm_row, "Label").icon_path new_label = self._get_table_item(vm_row, "Label", Qt.DecorationRole)
self.assertNotEqual(current_label_path, new_label_path, self.assertNotEqual(current_label.toImage(), new_label.toImage(),
"Label path did not change") "Label icon did not change")
self.assertEqual(
new_label_path, icon = QIcon.fromTheme(self.qapp.domains[target_vm_name].label.icon)
self.qapp.domains[target_vm_name].label.icon, icon = icon.pixmap(icon_size)
"Incorrect label")
self.assertEqual(new_label.toImage(), icon.toImage(), "Incorrect label")
def test_406_prop_change_template(self): def test_406_prop_change_template(self):
target_vm_name = "work" target_vm_name = "work"
vm_row = self._find_vm_row(target_vm_name) vm_row = self._find_vm_row(target_vm_name)
old_template = self._get_table_item(vm_row, "Template").text() old_template = self._get_table_item(vm_row, "Template")
new_template = None new_template = None
for vm in self.qapp.domains: for vm in self.qapp.domains:
if vm.klass == 'TemplateVM' and vm.name != old_template: if vm.klass == 'TemplateVM' and vm.name != old_template:
@ -908,10 +906,10 @@ class QubeManagerTest(unittest.TestCase):
["qvm-prefs", target_vm_name, "template", new_template]) ["qvm-prefs", target_vm_name, "template", new_template])
self.assertNotEqual(old_template, self.assertNotEqual(old_template,
self._get_table_item(vm_row, "Template").text(), self._get_table_item(vm_row, "Template"),
"Template did not change") "Template did not change")
self.assertEqual( self.assertEqual(
self._get_table_item(vm_row, "Template").text(), self._get_table_item(vm_row, "Template"),
self.qapp.domains[target_vm_name].template.name, self.qapp.domains[target_vm_name].template.name,
"Incorrect template") "Incorrect template")
@ -919,7 +917,7 @@ class QubeManagerTest(unittest.TestCase):
target_vm_name = "work" target_vm_name = "work"
vm_row = self._find_vm_row(target_vm_name) vm_row = self._find_vm_row(target_vm_name)
old_netvm = self._get_table_item(vm_row, "NetVM").text() old_netvm = self._get_table_item(vm_row, "NetVM")
new_netvm = None new_netvm = None
for vm in self.qapp.domains: for vm in self.qapp.domains:
if getattr(vm, "provides_network", False) and vm.name != old_netvm: if getattr(vm, "provides_network", False) and vm.name != old_netvm:
@ -932,10 +930,10 @@ class QubeManagerTest(unittest.TestCase):
["qvm-prefs", target_vm_name, "netvm", new_netvm]) ["qvm-prefs", target_vm_name, "netvm", new_netvm])
self.assertNotEqual(old_netvm, self.assertNotEqual(old_netvm,
self._get_table_item(vm_row, "NetVM").text(), self._get_table_item(vm_row, "NetVM"),
"NetVM did not change") "NetVM did not change")
self.assertEqual( self.assertEqual(
self._get_table_item(vm_row, "NetVM").text(), self._get_table_item(vm_row, "NetVM"),
self.qapp.domains[target_vm_name].netvm.name, self.qapp.domains[target_vm_name].netvm.name,
"Incorrect NetVM") "Incorrect NetVM")
@ -950,7 +948,7 @@ class QubeManagerTest(unittest.TestCase):
["qvm-features", "work", "interal", "1"]) ["qvm-features", "work", "interal", "1"])
self.assertEqual( self.assertEqual(
self._get_table_item(vm_row, "Internal").text(), self._get_table_item(vm_row, "Internal"),
"Yes", "Yes",
"Incorrect value for internal VM") "Incorrect value for internal VM")
@ -958,7 +956,7 @@ class QubeManagerTest(unittest.TestCase):
["qvm-features", "--unset", "work", "interal"]) ["qvm-features", "--unset", "work", "interal"])
self.assertEqual( self.assertEqual(
self._get_table_item(vm_row, "Internal").text(), self._get_table_item(vm_row, "Internal"),
"", "",
"Incorrect value for non-internal VM") "Incorrect value for non-internal VM")
@ -966,7 +964,7 @@ class QubeManagerTest(unittest.TestCase):
target_vm_name = "work" target_vm_name = "work"
vm_row = self._find_vm_row(target_vm_name) vm_row = self._find_vm_row(target_vm_name)
old_ip = self._get_table_item(vm_row, "IP").text() old_ip = self._get_table_item(vm_row, "IP")
new_ip = old_ip.replace(".0.", ".5.") new_ip = old_ip.replace(".0.", ".5.")
self.addCleanup( self.addCleanup(
@ -975,10 +973,10 @@ class QubeManagerTest(unittest.TestCase):
["qvm-prefs", target_vm_name, "ip", new_ip]) ["qvm-prefs", target_vm_name, "ip", new_ip])
self.assertNotEqual(old_ip, self.assertNotEqual(old_ip,
self._get_table_item(vm_row, "IP").text(), self._get_table_item(vm_row, "IP"),
"IP did not change") "IP did not change")
self.assertEqual( self.assertEqual(
self._get_table_item(vm_row, "IP").text(), self._get_table_item(vm_row, "IP"),
self.qapp.domains[target_vm_name].ip, self.qapp.domains[target_vm_name].ip,
"Incorrect IP") "Incorrect IP")
@ -996,7 +994,7 @@ class QubeManagerTest(unittest.TestCase):
["qvm-prefs", target_vm_name, "include_in_backups", str(new_value)]) ["qvm-prefs", target_vm_name, "include_in_backups", str(new_value)])
self.assertEqual( self.assertEqual(
self._get_table_item(vm_row, "Internal").text(), self._get_table_item(vm_row, "Internal"),
"Yes" if new_value else "", "Yes" if new_value else "",
"Incorrect value for include_in_backups") "Incorrect value for include_in_backups")
@ -1005,7 +1003,7 @@ class QubeManagerTest(unittest.TestCase):
target_timestamp = "2015-01-01 17:00:00" target_timestamp = "2015-01-01 17:00:00"
vm_row = self._find_vm_row(target_vm_name) vm_row = self._find_vm_row(target_vm_name)
old_value = self._get_table_item(vm_row, "Last backup").text() old_value = self._get_table_item(vm_row, "Last backup")
new_value = datetime.datetime.strptime( new_value = datetime.datetime.strptime(
target_timestamp, "%Y-%m-%d %H:%M:%S") target_timestamp, "%Y-%m-%d %H:%M:%S")
@ -1017,10 +1015,10 @@ class QubeManagerTest(unittest.TestCase):
str(int(new_value.timestamp()))]) str(int(new_value.timestamp()))])
self.assertNotEqual(old_value, self.assertNotEqual(old_value,
self._get_table_item(vm_row, "Last backup").text(), self._get_table_item(vm_row, "Last backup"),
"Last backup date did not change") "Last backup date did not change")
self.assertEqual( self.assertEqual(
self._get_table_item(vm_row, "Last backup").text(), self._get_table_item(vm_row, "Last backup"),
target_timestamp, target_timestamp,
"Incorrect Last backup date") "Incorrect Last backup date")
@ -1028,8 +1026,9 @@ class QubeManagerTest(unittest.TestCase):
target_vm_name = "work" target_vm_name = "work"
vm_row = self._find_vm_row(target_vm_name) vm_row = self._find_vm_row(target_vm_name)
old_default_dispvm =\ old_default_dispvm =\
self._get_table_item(vm_row, "Default DispVM").text() self._get_table_item(vm_row, "Default DispVM")
new_default_dispvm = None new_default_dispvm = None
for vm in self.qapp.domains: for vm in self.qapp.domains:
if getattr(vm, "template_for_dispvms", False) and vm.name !=\ if getattr(vm, "template_for_dispvms", False) and vm.name !=\
@ -1045,11 +1044,11 @@ class QubeManagerTest(unittest.TestCase):
self.assertNotEqual( self.assertNotEqual(
old_default_dispvm, old_default_dispvm,
self._get_table_item(vm_row, "Default DispVM").text(), self._get_table_item(vm_row, "Default DispVM"),
"Default DispVM did not change") "Default DispVM did not change")
self.assertEqual( self.assertEqual(
self._get_table_item(vm_row, "Default DispVM").text(), self._get_table_item(vm_row, "Default DispVM"),
self.qapp.domains[target_vm_name].default_dispvm.name, self.qapp.domains[target_vm_name].default_dispvm.name,
"Incorrect Default DispVM") "Incorrect Default DispVM")
@ -1064,7 +1063,7 @@ class QubeManagerTest(unittest.TestCase):
["qvm-prefs", target_vm_name, "template_for_dispvms", "True"]) ["qvm-prefs", target_vm_name, "template_for_dispvms", "True"])
self.assertEqual( self.assertEqual(
self._get_table_item(vm_row, "Is DVM Template").text(), self._get_table_item(vm_row, "Is DVM Template"),
"Yes", "Yes",
"Incorrect value for DVM Template") "Incorrect value for DVM Template")
@ -1072,7 +1071,7 @@ class QubeManagerTest(unittest.TestCase):
["qvm-prefs", "--default", target_vm_name, "template_for_dispvms"]) ["qvm-prefs", "--default", target_vm_name, "template_for_dispvms"])
self.assertEqual( self.assertEqual(
self._get_table_item(vm_row, "Is DVM Template").text(), self._get_table_item(vm_row, "Is DVM Template"),
"", "",
"Incorrect value for not DVM Template") "Incorrect value for not DVM Template")
@ -1088,19 +1087,17 @@ class QubeManagerTest(unittest.TestCase):
self._run_command_and_process_events( self._run_command_and_process_events(
["qvm-start", target_vm_name], timeout=60) ["qvm-start", target_vm_name], timeout=60)
status_item = self._get_table_item(vm_row, "State") displayed_state = self._get_table_item(vm_row, "State")
displayed_power_state = status_item.on_icon.status self.assertEqual(displayed_state['power'], 'Running',
self.assertEqual(displayed_power_state, 3,
"Power state failed to update on start") "Power state failed to update on start")
self._run_command_and_process_events( self._run_command_and_process_events(
["qvm-shutdown", "--wait", target_vm_name], timeout=30) ["qvm-shutdown", "--wait", target_vm_name], timeout=30)
displayed_power_state = status_item.on_icon.status displayed_state = self._get_table_item(vm_row, "State")
self.assertEqual(displayed_power_state, 0, self.assertEqual(displayed_state['power'], 'Halted',
"Power state failed to update on shutdown") "Power state failed to update on shutdown")
def test_415_template_vm_started(self): def test_415_template_vm_started(self):
@ -1116,9 +1113,8 @@ class QubeManagerTest(unittest.TestCase):
if target_vm_name: if target_vm_name:
break break
for i in range(self.dialog.table.rowCount()): for i in range(self.dialog.table.model().rowCount()):
self._get_table_item(i, "State").update_vm_state =\ self._get_table_vminfo(i).update = unittest.mock.Mock()
unittest.mock.Mock()
self.addCleanup( self.addCleanup(
subprocess.call, subprocess.call,
@ -1126,12 +1122,12 @@ class QubeManagerTest(unittest.TestCase):
self._run_command_and_process_events( self._run_command_and_process_events(
["qvm-start", target_vm_name], timeout=60) ["qvm-start", target_vm_name], timeout=60)
for i in range(self.dialog.table.rowCount()): for i in range(self.dialog.table.model().rowCount()):
call_count = self._get_table_item( call_count = self._get_table_vminfo(
i, "State").update_vm_state.call_count i).update.call_count
if self._get_table_item(i, "Template").text() == target_vm_name: if self._get_table_item(i, "Template") == target_vm_name:
self.assertGreater(call_count, 0) self.assertGreater(call_count, 0)
elif self._get_table_item(i, "Name").text() == target_vm_name: elif self._get_table_item(i, "Name") == target_vm_name:
self.assertGreater(call_count, 0) self.assertGreater(call_count, 0)
else: else:
self.assertEqual(call_count, 0) self.assertEqual(call_count, 0)
@ -1168,15 +1164,15 @@ class QubeManagerTest(unittest.TestCase):
"Same logs found for dom0 and non-adminVM") "Same logs found for dom0 and non-adminVM")
def _find_vm_row(self, vm_name): def _find_vm_row(self, vm_name):
for row in range(self.dialog.table.rowCount()): for row in range(self.dialog.table.model().rowCount()):
name = self._get_table_item(row, "Name") name = self._get_table_item(row, "Name")
if name.text() == vm_name: if name == vm_name:
return row return row
return None return None
def _count_visible_table_rows(self): def _count_visible_table_rows(self):
result = 0 result = 0
for i in range(self.dialog.table.rowCount()): for i in range(self.dialog.table.model().rowCount()):
if not self.dialog.table.isRowHidden(i): if not self.dialog.table.isRowHidden(i):
result += 1 result += 1
return result return result
@ -1210,54 +1206,51 @@ class QubeManagerTest(unittest.TestCase):
def _create_set_of_current_vms(self): def _create_set_of_current_vms(self):
result = set() result = set()
for i in range(self.dialog.table.rowCount()): for i in range(self.dialog.table.model().rowCount()):
result.add(self._get_table_item(i, "Name").vm.name) result.add(self._get_table_item(i, "Name"))
return result return result
def _select_admin_vm(self): def _select_admin_vm(self):
for row in range(self.dialog.table.rowCount()): for row in range(self.dialog.table.model().rowCount()):
template = self.dialog.table.item( template = self._get_table_item(row, "Template")
row, self.dialog.columns_indices["Template"]) if template == 'AdminVM':
if template.text() == 'AdminVM': index = self.dialog.table.model().index(row, 0)
self.dialog.table.setCurrentItem(template) self.dialog.table.setCurrentIndex(index)
return template.vm return index.data(Qt.UserRole).vm
return None return None
def _select_non_admin_vm(self, running=None): def _select_non_admin_vm(self, running=None):
for row in range(self.dialog.table.rowCount()): for row in range(self.dialog.table.model().rowCount()):
template = self.dialog.table.item( template = self._get_table_item(row, "Template")
row, self.dialog.columns_indices["Template"]) vm = self._get_table_vm(row)
status = self.dialog.table.item( if template != 'AdminVM' and \
row, self.dialog.columns_indices["State"])
if template.text() != 'AdminVM' and \
(running is None (running is None
or (running and status.on_icon.status == 3) or (running and vm.is_running())
or (not running and status.on_icon.status != 3)): or (not running and not vm.is_running())):
self.dialog.table.setCurrentItem(template) index = self.dialog.table.model().index(row, 0)
return template.vm self.dialog.table.setCurrentIndex(index)
return vm
return None return None
def _select_templatevm(self, running=None): def _select_templatevm(self, running=None):
for row in range(self.dialog.table.rowCount()): for row in range(self.dialog.table.model().rowCount()):
template = self.dialog.table.item( template = self._get_table_item(row, "Template")
row, self.dialog.columns_indices["Template"]) vm = self._get_table_vm(row)
status = self.dialog.table.item( if template == 'TemplateVM' and \
row, self.dialog.columns_indices["State"])
if template.text() == 'TemplateVM' and \
(running is None (running is None
or (running and status.on_icon.status == 3) or (running and vm.is_running())
or (not running and status.on_icon.status != 3)): or (not running and not vm.is_running())):
self.dialog.table.setCurrentItem(template) index = self.dialog.table.model().index(row, 0)
return template.vm self.dialog.table.setCurrentIndex(index)
return vm
return None return None
def __check_sorting(self, column_name): def __check_sorting(self, column_name):
last_text = None last_text = None
last_vm = None last_vm = None
for row in range(self.dialog.table.rowCount()): for row in range(self.dialog.table.model().rowCount()):
vm = self._get_table_item(row, "Name")
vm = self._get_table_item(row, "Name").vm.name text = self._get_table_item(row, column_name)
text = self._get_table_item(row, column_name).text().lower()
if row == 0: if row == 0:
self.assertEqual(vm, "dom0", "dom0 is not sorted first") self.assertEqual(vm, "dom0", "dom0 is not sorted first")
@ -1267,24 +1260,27 @@ class QubeManagerTest(unittest.TestCase):
else: else:
if last_text == text: if last_text == text:
self.assertGreater( self.assertGreater(
vm, last_vm, vm.lower(), last_vm.lower(),
"Incorrect sorting for {}".format(column_name)) "Incorrect sorting for {}".format(column_name))
else: else:
self.assertGreater( self.assertGreater(
text, last_text, text.lower(), last_text.lower(),
"Incorrect sorting for {}".format(column_name)) "Incorrect sorting for {}".format(column_name))
last_text = text last_text = text
last_vm = vm last_vm = vm
def _get_table_item(self, row, column_name): def _get_table_vminfo(self, row):
value = self.dialog.table.cellWidget( model = self.dialog.table.model()
row, self.dialog.columns_indices[column_name]) return model.index(row, 0).data(Qt.UserRole)
if not value:
value = self.dialog.table.item(
row, self.dialog.columns_indices[column_name])
return value def _get_table_vm(self, row):
model = self.dialog.table.model()
return model.index(row, 0).data(Qt.UserRole).vm
def _get_table_item(self, row, column_name, role = Qt.DisplayRole):
model = self.dialog.table.model()
column = self.dialog.qubes_model.columns_indices.index(column_name)
return model.index(row, column).data(role)
class QubeManagerThreadTest(unittest.TestCase): class QubeManagerThreadTest(unittest.TestCase):
def test_01_startvm_thread(self): def test_01_startvm_thread(self):

View File

@ -71,7 +71,6 @@ rm -rf $RPM_BUILD_ROOT
%{python3_sitelib}/qubesmanager/__pycache__ %{python3_sitelib}/qubesmanager/__pycache__
%{python3_sitelib}/qubesmanager/__init__.py %{python3_sitelib}/qubesmanager/__init__.py
%{python3_sitelib}/qubesmanager/clipboard.py %{python3_sitelib}/qubesmanager/clipboard.py
%{python3_sitelib}/qubesmanager/table_widgets.py
%{python3_sitelib}/qubesmanager/appmenu_select.py %{python3_sitelib}/qubesmanager/appmenu_select.py
%{python3_sitelib}/qubesmanager/backup.py %{python3_sitelib}/qubesmanager/backup.py
%{python3_sitelib}/qubesmanager/backup_utils.py %{python3_sitelib}/qubesmanager/backup_utils.py

View File

@ -11,6 +11,9 @@ class QubesVMNotStartedError(BaseException):
class QubesPropertyAccessError(BaseException): class QubesPropertyAccessError(BaseException):
pass pass
class QubesNoSuchPropertyError(BaseException):
pass
class QubesDaemonNoResponseError(BaseException): class QubesDaemonNoResponseError(BaseException):
pass pass

View File

@ -52,21 +52,6 @@
<property name="sizeConstraint"> <property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum> <enum>QLayout::SetDefaultConstraint</enum>
</property> </property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>0</number>
</property>
<item row="0" column="0"> <item row="0" column="0">
<layout class="QHBoxLayout" name="searchContainer"> <layout class="QHBoxLayout" name="searchContainer">
<property name="spacing"> <property name="spacing">
@ -85,7 +70,7 @@
</layout> </layout>
</item> </item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QTableWidget" name="table"> <widget class="QTableView" name="table">
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>0</width> <width>0</width>
@ -140,21 +125,9 @@
<property name="cornerButtonEnabled"> <property name="cornerButtonEnabled">
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="rowCount">
<number>10</number>
</property>
<property name="columnCount">
<number>14</number>
</property>
<attribute name="horizontalHeaderCascadingSectionResizes"> <attribute name="horizontalHeaderCascadingSectionResizes">
<bool>false</bool> <bool>false</bool>
</attribute> </attribute>
<attribute name="horizontalHeaderMinimumSectionSize">
<number>150</number>
</attribute>
<attribute name="horizontalHeaderDefaultSectionSize">
<number>150</number>
</attribute>
<attribute name="verticalHeaderVisible"> <attribute name="verticalHeaderVisible">
<bool>false</bool> <bool>false</bool>
</attribute> </attribute>
@ -292,25 +265,6 @@ Template</string>
<property name="title"> <property name="title">
<string>&amp;View</string> <string>&amp;View</string>
</property> </property>
<addaction name="action_vm_type"/>
<addaction name="action_label"/>
<addaction name="action_state"/>
<addaction name="action_template"/>
<addaction name="action_netvm"/>
<addaction name="action_size_on_disk"/>
<addaction name="action_internal"/>
<addaction name="action_ip"/>
<addaction name="action_backups"/>
<addaction name="action_last_backup"/>
<addaction name="action_dispvm_template"/>
<addaction name="action_is_dvm_template"/>
<addaction name="action_virt_mode"/>
<addaction name="separator"/>
<addaction name="action_toolbar"/>
<addaction name="action_menubar"/>
<addaction name="separator"/>
<addaction name="separator"/>
<addaction name="action_search"/>
</widget> </widget>
<widget class="QMenu" name="menu_vm"> <widget class="QMenu" name="menu_vm">
<property name="title"> <property name="title">