hydrus/hydrus/client/gui/ClientGUIFunctions.py

456 lines
12 KiB
Python
Raw Normal View History

2019-09-11 21:51:09 +00:00
import collections
2020-04-22 21:00:35 +00:00
2019-11-14 03:56:30 +00:00
from qtpy import QtCore as QC
from qtpy import QtWidgets as QW
from qtpy import QtGui as QG
2020-04-22 21:00:35 +00:00
from hydrus.core import HydrusConstants as HC
from hydrus.core import HydrusData
from hydrus.core import HydrusExceptions
from hydrus.core import HydrusGlobals as HG
from hydrus.client import ClientTags
from hydrus.client.gui import QtPorting as QP
2019-06-26 21:27:18 +00:00
def ApplyContentApplicationCommandToMedia( parent, command, media ):
data = command.GetData()
( service_key, content_type, action, value ) = data
try:
service = HG.client_controller.services_manager.GetService( service_key )
except HydrusExceptions.DataMissing:
command_processed = False
return command_processed
service_type = service.GetServiceType()
hashes = set()
for m in media:
2019-09-11 21:51:09 +00:00
hashes.add( m.GetHash() )
2019-06-26 21:27:18 +00:00
2020-03-11 21:52:11 +00:00
if service_type in HC.REAL_TAG_SERVICES:
2019-06-26 21:27:18 +00:00
tag = value
can_add = False
can_pend = False
can_delete = False
can_petition = True
can_rescind_pend = False
can_rescind_petition = False
for m in media:
tags_manager = m.GetTagsManager()
2019-10-02 23:38:59 +00:00
current = tags_manager.GetCurrent( service_key, ClientTags.TAG_DISPLAY_STORAGE )
pending = tags_manager.GetPending( service_key, ClientTags.TAG_DISPLAY_STORAGE )
petitioned = tags_manager.GetPetitioned( service_key, ClientTags.TAG_DISPLAY_STORAGE )
2019-06-26 21:27:18 +00:00
if tag not in current:
can_add = True
if tag not in current and tag not in pending:
can_pend = True
if tag in current and action == HC.CONTENT_UPDATE_FLIP:
can_delete = True
if tag in current and tag not in petitioned and action == HC.CONTENT_UPDATE_FLIP:
can_petition = True
if tag in pending and action == HC.CONTENT_UPDATE_FLIP:
can_rescind_pend = True
if tag in petitioned:
can_rescind_petition = True
reason = None
if service_type == HC.LOCAL_TAG:
tags = [ tag ]
if can_add:
content_update_action = HC.CONTENT_UPDATE_ADD
tag_parents_manager = HG.client_controller.tag_parents_manager
parents = tag_parents_manager.GetParents( service_key, tag )
tags.extend( parents )
elif can_delete:
content_update_action = HC.CONTENT_UPDATE_DELETE
else:
return True
rows = [ ( tag, hashes ) for tag in tags ]
else:
if can_rescind_petition:
content_update_action = HC.CONTENT_UPDATE_RESCIND_PETITION
rows = [ ( tag, hashes ) ]
elif can_pend:
tags = [ tag ]
content_update_action = HC.CONTENT_UPDATE_PEND
tag_parents_manager = HG.client_controller.tag_parents_manager
parents = tag_parents_manager.GetParents( service_key, tag )
tags.extend( parents )
rows = [ ( tag, hashes ) for tag in tags ]
elif can_rescind_pend:
content_update_action = HC.CONTENT_UPDATE_RESCIND_PEND
rows = [ ( tag, hashes ) ]
elif can_petition:
message = 'Enter a reason for this tag to be removed. A janitor will review your petition.'
2020-04-22 21:00:35 +00:00
from hydrus.client.gui import ClientGUIDialogs
2019-06-26 21:27:18 +00:00
with ClientGUIDialogs.DialogTextEntry( parent, message ) as dlg:
2019-11-14 03:56:30 +00:00
if dlg.exec() == QW.QDialog.Accepted:
2019-06-26 21:27:18 +00:00
content_update_action = HC.CONTENT_UPDATE_PETITION
reason = dlg.GetValue()
rows = [ ( tag, hashes ) ]
else:
return True
else:
return True
content_updates = [ HydrusData.ContentUpdate( HC.CONTENT_TYPE_MAPPINGS, content_update_action, row, reason = reason ) for row in rows ]
elif service_type in ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ):
2019-09-11 21:51:09 +00:00
if action in ( HC.CONTENT_UPDATE_SET, HC.CONTENT_UPDATE_FLIP ):
2019-06-26 21:27:18 +00:00
2019-09-11 21:51:09 +00:00
rating = value
2019-06-26 21:27:18 +00:00
2019-09-11 21:51:09 +00:00
can_set = False
can_unset = False
2019-06-26 21:27:18 +00:00
2019-09-11 21:51:09 +00:00
for m in media:
2019-06-26 21:27:18 +00:00
2019-09-11 21:51:09 +00:00
ratings_manager = m.GetRatingsManager()
2019-06-26 21:27:18 +00:00
2019-09-11 21:51:09 +00:00
current_rating = ratings_manager.GetRating( service_key )
2019-06-26 21:27:18 +00:00
2019-09-11 21:51:09 +00:00
if current_rating == rating and action == HC.CONTENT_UPDATE_FLIP:
can_unset = True
else:
can_set = True
2019-06-26 21:27:18 +00:00
2019-09-11 21:51:09 +00:00
if can_set:
row = ( rating, hashes )
elif can_unset:
row = ( None, hashes )
else:
return True
2019-06-26 21:27:18 +00:00
2019-09-11 21:51:09 +00:00
content_updates = [ HydrusData.ContentUpdate( HC.CONTENT_TYPE_RATINGS, HC.CONTENT_UPDATE_ADD, row ) ]
2019-06-26 21:27:18 +00:00
2019-09-11 21:51:09 +00:00
elif action in ( HC.CONTENT_UPDATE_INCREMENT, HC.CONTENT_UPDATE_DECREMENT ):
2019-06-26 21:27:18 +00:00
2019-09-11 21:51:09 +00:00
if service_type == HC.LOCAL_RATING_NUMERICAL:
if action == HC.CONTENT_UPDATE_INCREMENT:
direction = 1
initialisation_rating = 0.0
elif action == HC.CONTENT_UPDATE_DECREMENT:
direction = -1
initialisation_rating = 1.0
num_stars = service.GetNumStars()
if service.AllowZero():
num_stars += 1
one_star_value = 1.0 / ( num_stars - 1 )
ratings_to_hashes = collections.defaultdict( set )
for m in media:
ratings_manager = m.GetRatingsManager()
current_rating = ratings_manager.GetRating( service_key )
if current_rating is None:
new_rating = initialisation_rating
else:
new_rating = current_rating + ( one_star_value * direction )
new_rating = max( min( new_rating, 1.0 ), 0.0 )
if current_rating != new_rating:
ratings_to_hashes[ new_rating ].add( m.GetHash() )
content_updates = [ HydrusData.ContentUpdate( HC.CONTENT_TYPE_RATINGS, HC.CONTENT_UPDATE_ADD, ( rating, hashes ) ) for ( rating, hashes ) in ratings_to_hashes.items() ]
else:
return True
2019-06-26 21:27:18 +00:00
else:
return False
2019-09-11 21:51:09 +00:00
if len( content_updates ) > 0:
HG.client_controller.Write( 'content_updates', { service_key : content_updates } )
2019-06-26 21:27:18 +00:00
return True
2020-02-26 22:28:52 +00:00
def ClientToScreen( win: QW.QWidget, pos: QC.QPoint ) -> QC.QPoint:
2019-06-26 21:27:18 +00:00
2019-12-11 23:18:37 +00:00
tlw = win.window()
2019-11-14 03:56:30 +00:00
2019-12-11 23:18:37 +00:00
if win.isVisible() and tlw.isVisible():
2019-06-26 21:27:18 +00:00
2019-11-14 03:56:30 +00:00
return win.mapToGlobal( pos )
2019-06-26 21:27:18 +00:00
else:
2019-11-14 03:56:30 +00:00
return QC.QPoint( 50, 50 )
2019-06-26 21:27:18 +00:00
MAGIC_TEXT_PADDING = 1.1
def ConvertTextToPixels( window, char_dimensions ):
( char_cols, char_rows ) = char_dimensions
2019-11-14 03:56:30 +00:00
return ( int( window.fontMetrics().boundingRect( char_cols * 'x' ).width() * MAGIC_TEXT_PADDING ), int( char_rows * window.fontMetrics().height() * MAGIC_TEXT_PADDING ) )
2019-06-26 21:27:18 +00:00
def ConvertTextToPixelWidth( window, char_cols ):
2019-11-14 03:56:30 +00:00
return int( window.fontMetrics().boundingRect( char_cols * 'x' ).width() * MAGIC_TEXT_PADDING )
2019-06-26 21:27:18 +00:00
2020-02-26 22:28:52 +00:00
def DialogIsOpen():
tlws = QW.QApplication.topLevelWidgets()
for tlw in tlws:
if isinstance( tlw, QP.Dialog ) and tlw.isModal():
return True
return False
2020-04-22 21:00:35 +00:00
def EscapeMnemonics( str ):
return str.replace( "&", "&&" )
2019-12-11 23:18:37 +00:00
def GetTLWParents( widget ):
2019-06-26 21:27:18 +00:00
2019-12-11 23:18:37 +00:00
widget_tlw = widget.window()
2019-06-26 21:27:18 +00:00
2019-12-11 23:18:37 +00:00
parent_tlws = []
2019-06-26 21:27:18 +00:00
2019-12-11 23:18:37 +00:00
parent = widget_tlw.parentWidget()
2019-06-26 21:27:18 +00:00
while parent is not None:
2019-12-11 23:18:37 +00:00
parent_tlw = parent.window()
2019-06-26 21:27:18 +00:00
2019-12-11 23:18:37 +00:00
parent_tlws.append( parent_tlw )
parent = parent_tlw.parentWidget()
2019-06-26 21:27:18 +00:00
2019-12-11 23:18:37 +00:00
return parent_tlws
2019-06-26 21:27:18 +00:00
2019-11-14 03:56:30 +00:00
def IsQtAncestor( child, ancestor, through_tlws = False ):
2019-06-26 21:27:18 +00:00
2019-07-17 22:10:19 +00:00
if child == ancestor:
return True
2019-06-26 21:27:18 +00:00
parent = child
if through_tlws:
while not parent is None:
if parent == ancestor:
return True
2019-11-14 03:56:30 +00:00
parent = parent.parentWidget()
2019-06-26 21:27:18 +00:00
else:
2019-11-14 03:56:30 +00:00
# only works within window
return ancestor.isAncestorOf( child )
2019-06-26 21:27:18 +00:00
return False
def NotebookScreenToHitTest( notebook, screen_position ):
2019-12-05 05:29:32 +00:00
tab_pos = notebook.tabBar().mapFromGlobal( screen_position )
2019-06-26 21:27:18 +00:00
2019-12-05 05:29:32 +00:00
return notebook.tabBar().tabAt( tab_pos )
2019-06-26 21:27:18 +00:00
def SetBitmapButtonBitmap( button, bitmap ):
2019-11-14 03:56:30 +00:00
# old wx stuff, but still basically relevant
2019-06-26 21:27:18 +00:00
# the button's bitmap, retrieved via GetBitmap, is not the same as the one we gave it!
# hence testing bitmap vs that won't work to save time on an update loop, so we'll just save it here custom
2019-11-14 03:56:30 +00:00
# this isn't a big memory deal for our purposes since they are small and mostly if not all from the GlobalPixmaps library so shared anyway
2019-06-26 21:27:18 +00:00
if hasattr( button, 'last_bitmap' ):
if button.last_bitmap == bitmap:
return
2019-11-14 03:56:30 +00:00
button.setIcon( QG.QIcon( bitmap ) )
button.setIconSize( bitmap.size() )
2019-06-26 21:27:18 +00:00
button.last_bitmap = bitmap
2019-12-11 23:18:37 +00:00
def TLWIsActive( window ):
2019-06-26 21:27:18 +00:00
2019-11-20 23:10:46 +00:00
return window.window() == QW.QApplication.activeWindow()
2019-06-26 21:27:18 +00:00
2019-12-11 23:18:37 +00:00
def TLWOrChildIsActive( win ):
current_focus_tlw = QW.QApplication.activeWindow()
if current_focus_tlw is None:
return False
if current_focus_tlw == win:
return True
if win in GetTLWParents( current_focus_tlw ):
return True
return False
def WidgetOrAnyTLWChildHasFocus( window ):
2019-06-26 21:27:18 +00:00
2019-11-20 23:10:46 +00:00
active_window = QW.QApplication.activeWindow()
2019-11-14 03:56:30 +00:00
2019-11-20 23:10:46 +00:00
if window == active_window:
2019-06-26 21:27:18 +00:00
2019-11-20 23:10:46 +00:00
return True
2019-06-26 21:27:18 +00:00
2019-11-20 23:10:46 +00:00
widget = QW.QApplication.focusWidget()
2019-11-14 03:56:30 +00:00
2019-11-20 23:10:46 +00:00
if widget is None:
2019-12-11 23:18:37 +00:00
# take active window in lieu of focus, if it is unavailable
2019-11-20 23:10:46 +00:00
widget = active_window
2019-06-26 21:27:18 +00:00
2019-11-20 23:10:46 +00:00
while widget is not None:
2019-06-26 21:27:18 +00:00
2019-11-20 23:10:46 +00:00
if widget == window:
2019-06-26 21:27:18 +00:00
return True
2019-11-20 23:10:46 +00:00
widget = widget.parentWidget()
2019-06-26 21:27:18 +00:00
return False