hydrus/include/ClientGUIFunctions.py

414 lines
12 KiB
Python
Raw Normal View History

2019-09-11 21:51:09 +00:00
import collections
2019-10-02 23:38:59 +00:00
from . import ClientTags
2019-06-26 21:27:18 +00:00
from . import HydrusConstants as HC
from . import HydrusData
from . import HydrusExceptions
from . import HydrusGlobals as HG
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
from . 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
if service_type in HC.TAG_SERVICES:
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.'
from . import ClientGUIDialogs
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
def ClientToScreen( win, pos ):
2019-11-14 03:56:30 +00:00
if isinstance( pos, tuple ): pos = QP.TupleToQPoint( pos )
2019-06-26 21:27:18 +00:00
2019-11-14 03:56:30 +00:00
tlp = win.window()
if win.isVisible() and tlp.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
def GetTLPParents( window ):
2019-11-14 03:56:30 +00:00
window = window.window()
2019-06-26 21:27:18 +00:00
parents = []
2019-11-14 03:56:30 +00:00
parent = window.parentWidget()
2019-06-26 21:27:18 +00:00
while parent is not None:
parents.append( parent )
2019-11-14 03:56:30 +00:00
parent = parent.parentWidget()
2019-06-26 21:27:18 +00:00
return parents
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-11-14 03:56:30 +00:00
position = notebook.mapFromGlobal( screen_position )
2019-06-26 21:27:18 +00:00
2019-11-14 03:56:30 +00:00
return notebook.tabBar().tabAt( position )
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-11-20 23:10:46 +00:00
def TLPIsActive( 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
def WindowOrAnyTLPChildHasFocus( window ):
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:
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